do not destroy and rerender sub widgets if not necessary

add failing test on rerendering sub widgets...
This commit is contained in:
Géry Debongnie
2019-01-27 22:16:00 +01:00
parent 9e0d1db8e4
commit 851d01b7ad
4 changed files with 60 additions and 14 deletions
+11 -1
View File
@@ -25,6 +25,8 @@ interface Meta<T extends WEnv> {
isDestroyed: boolean;
parent: Widget<T> | null;
children: { [key: number]: Widget<T> };
// children mapping: from templateID to widgetID
cmap: { [key: number]: number };
}
const patch = init([sdListeners, sdAttrs]);
@@ -43,6 +45,7 @@ export class Widget<T extends WEnv> {
env: T;
state: Object = {};
props: any;
refs: { [key: string]: Widget<T> | HTMLElement | undefined } = {}; // either HTMLElement or Widget
//--------------------------------------------------------------------------
@@ -51,6 +54,7 @@ export class Widget<T extends WEnv> {
constructor(parent: Widget<T> | T, props?: any) {
wl.push(this);
this.props = props;
let id: number;
let p: Widget<T> | null = null;
if (parent instanceof Widget) {
@@ -69,7 +73,8 @@ export class Widget<T extends WEnv> {
isMounted: false,
isDestroyed: false,
parent: p,
children: {}
children: {},
cmap: {}
};
}
@@ -139,6 +144,11 @@ export class Widget<T extends WEnv> {
}
}
updateProps(props?: any): Promise<void> {
this.props = props;
return this.render();
}
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
+29 -7
View File
@@ -691,11 +691,6 @@ const widgetDirective: Directive = {
priority: 100,
atNodeEncounter({ ctx, value, node, qweb }): boolean {
ctx.rootContext.shouldDefineOwner = true;
let dummyID = ctx.generateID();
let defID = ctx.generateID();
ctx.addLine(`let _${dummyID} = {}; // DUMMY`);
ctx.addLine(`let _${dummyID}_index = c${ctx.parentNode}.length;`);
ctx.addLine(`c${ctx.parentNode}.push(_${dummyID});`);
let props = node.getAttribute("t-props");
if (props) {
props = props.trim();
@@ -713,21 +708,48 @@ const widgetDirective: Directive = {
props = qweb._formatExpression(props);
}
}
let dummyID = ctx.generateID();
let defID = ctx.generateID();
let widgetID = ctx.generateID();
ctx.addLine(`let _${dummyID} = {}; // DUMMY`);
ctx.addLine(`let _${dummyID}_index = c${ctx.parentNode}.length;`);
ctx.addLine(`c${ctx.parentNode}.push(_${dummyID});`);
ctx.addLine(`let def${defID};`);
ctx.addLine(`if (${widgetID} in context.__widget__.cmap) {`);
ctx.indent();
ctx.addLine(
`let curWidget = context.__widget__.children[context.__widget__.cmap[${widgetID}]]`
);
ctx.addLine(
`def${defID} = curWidget.updateProps(${props}).then(()=>{vnode=curWidget.__widget__.vnode;c${
ctx.parentNode
}[_${dummyID}_index]=vnode;vnode.data.hook = {remove(){curWidget.destroy()}}});`
);
ctx.dedent();
ctx.addLine("} else {");
ctx.indent();
ctx.addLine(
`let _${widgetID} = new context.widgets['${value}'](owner, ${props});`
);
ctx.addLine(
`let def${defID} = _${widgetID}._start().then(() => _${widgetID}._render()).then(vnode=>{c${
`context.__widget__.cmap[${widgetID}] = _${widgetID}.__widget__.id`
);
ctx.addLine(
`def${defID} = _${widgetID}._start().then(() => _${widgetID}._render()).then(vnode=>{c${
ctx.parentNode
}[_${dummyID}_index]=vnode;vnode.data.hook = {create(_,vn){_${widgetID}._mount(vn)},remove(){_${widgetID}.destroy()}}});`
);
ctx.addLine(`extra.promises.push(def${defID});`);
let ref = node.getAttribute("t-ref");
if (ref) {
ctx.addLine(`context.refs['${ref}'] = _${widgetID};`);
}
ctx.dedent();
ctx.addLine("}");
ctx.addLine(`extra.promises.push(def${defID});`);
return true;
}
};
+1 -6
View File
@@ -56,10 +56,5 @@ export class Discuss extends Widget<Env> {
class ColorWidget extends Widget<Env> {
name = "colorwidget";
template = `<div>Current Color: <t t-esc="state.color"/></div>`;
state: { color: "red" | "blue" };
constructor(parent: Widget<Env>, props: { color: "red" | "blue" }) {
super(parent);
this.state = { color: props.color };
}
template = `<div>Current Color: <t t-esc="props.color"/></div>`;
}
+19
View File
@@ -516,6 +516,25 @@ describe("composition", () => {
expect(children(widget)[0].env).toBe(env);
});
test("rerendering a widget with a sub widget", async () => {
class ParentWidget extends Widget<WEnv> {
template = `<div><t t-widget="Counter"/></div>`;
widgets = { Counter };
}
const widget = new ParentWidget(env);
await widget.mount(fixture);
const button = fixture.getElementsByTagName("button")[0];
await button.click();
await nextTick();
expect(fixture.innerHTML).toBe(
"<div><div>1<button>Inc</button></div></div>"
);
await widget.render();
expect(fixture.innerHTML).toBe(
"<div><div>1<button>Inc</button></div></div>"
);
});
});
describe("props evaluation (with t-props directive)", () => {