From ad9fb774583edd06c9592870179cfe56c893444b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Thu, 21 Mar 2019 16:06:06 +0100 Subject: [PATCH] fix: force children to rerender when env changes --- src/component.ts | 20 ++++++++++++-------- src/qweb.ts | 8 ++++++-- tests/__snapshots__/component.test.ts.snap | 8 ++++---- tests/component.test.ts | 17 +++++++++++++++++ 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/component.ts b/src/component.ts index 59aa2481..373f7e96 100644 --- a/src/component.ts +++ b/src/component.ts @@ -224,11 +224,11 @@ export class Component< } } - async render(): Promise { + async render(force: boolean = false): Promise { if (this.__widget__.isDestroyed) { return; } - const renderVDom = this._render(); + const renderVDom = this._render(force); const renderId = this.__widget__.renderId; const vnode = await renderVDom; if (renderId === this.__widget__.renderId) { @@ -281,16 +281,19 @@ export class Component< } Object.assign(this.env, nextEnv); if (this.__widget__.isMounted) { - return this.render(); + return this.render(true); } } - async updateProps(nextProps: Props): Promise { - if (nextProps === this.__widget__.renderProps) { + async updateProps( + nextProps: Props, + forceUpdate: boolean = false + ): Promise { + if (nextProps === this.__widget__.renderProps && !forceUpdate) { await this.__widget__.renderPromise; return; } - const shouldUpdate = this.shouldUpdate(nextProps); + const shouldUpdate = forceUpdate || this.shouldUpdate(nextProps); return shouldUpdate ? this._updateProps(nextProps) : Promise.resolve(); } @@ -348,13 +351,14 @@ export class Component< return this.__widget__.renderPromise; } - async _render(): Promise { + async _render(force: boolean = false): Promise { this.__widget__.renderId++; const promises: Promise[] = []; const template = this.inlineTemplate || this.template; let vnode = this.env.qweb.render(template, this, { promises, - handlers: this.__widget__.boundHandlers + handlers: this.__widget__.boundHandlers, + forceUpdate: force }); // this part is critical for the patching process to be done correctly. The diff --git a/src/qweb.ts b/src/qweb.ts index 1fa67d21..ec7d796d 100644 --- a/src/qweb.ts +++ b/src/qweb.ts @@ -947,7 +947,9 @@ const widgetDirective: Directive = { // check if we can reuse current rendering promise ctx.addIf(`w${widgetID} && w${widgetID}.__widget__.renderPromise`); ctx.addIf(`w${widgetID}.__widget__.isStarted`); - ctx.addLine(`def${defID} = w${widgetID}.updateProps(props${widgetID});`); + ctx.addLine( + `def${defID} = w${widgetID}.updateProps(props${widgetID}, extra.forceUpdate);` + ); ctx.addElse(); ctx.addLine(`isNew${widgetID} = true`); ctx.addIf(`props${widgetID} === w${widgetID}.__widget__.renderProps`); @@ -961,7 +963,9 @@ const widgetDirective: Directive = { ctx.addIf(`!def${defID}`); ctx.addIf(`w${widgetID}`); - ctx.addLine(`def${defID} = w${widgetID}.updateProps(props${widgetID});`); + ctx.addLine( + `def${defID} = w${widgetID}.updateProps(props${widgetID}, extra.forceUpdate);` + ); ctx.addElse(); ctx.addLine( `w${widgetID} = new context.widgets['${value}'](owner, props${widgetID});` diff --git a/tests/__snapshots__/component.test.ts.snap b/tests/__snapshots__/component.test.ts.snap index ac43cec1..af1c3683 100644 --- a/tests/__snapshots__/component.test.ts.snap +++ b/tests/__snapshots__/component.test.ts.snap @@ -34,7 +34,7 @@ exports[`composition sub widgets with some state rendered in a loop 1`] = ` let isNew7 = !w7; if (w7 && w7.__widget__.renderPromise) { if (w7.__widget__.isStarted) { - def6 = w7.updateProps(props7); + def6 = w7.updateProps(props7, extra.forceUpdate); } else { isNew7 = true if (props7 === w7.__widget__.renderProps) { @@ -47,7 +47,7 @@ exports[`composition sub widgets with some state rendered in a loop 1`] = ` } if (!def6) { if (w7) { - def6 = w7.updateProps(props7); + def6 = w7.updateProps(props7, extra.forceUpdate); } else { w7 = new context.widgets['ChildWidget'](owner, props7); context.__widget__.cmap[key8] = w7.__widget__.id; @@ -86,7 +86,7 @@ exports[`random stuff/miscellaneous snapshotting compiled code 1`] = ` let isNew4 = !w4; if (w4 && w4.__widget__.renderPromise) { if (w4.__widget__.isStarted) { - def3 = w4.updateProps(props4); + def3 = w4.updateProps(props4, extra.forceUpdate); } else { isNew4 = true if (props4 === w4.__widget__.renderProps) { @@ -99,7 +99,7 @@ exports[`random stuff/miscellaneous snapshotting compiled code 1`] = ` } if (!def3) { if (w4) { - def3 = w4.updateProps(props4); + def3 = w4.updateProps(props4, extra.forceUpdate); } else { w4 = new context.widgets['child'](owner, props4); context.__widget__.cmap[key5] = w4.__widget__.id; diff --git a/tests/component.test.ts b/tests/component.test.ts index 9fe53bb3..d15c43ef 100644 --- a/tests/component.test.ts +++ b/tests/component.test.ts @@ -1171,4 +1171,21 @@ describe("updating environment", () => { await widget.updateEnv({ someKey: "rerendered" }); expect(fixture.innerHTML).toBe("
rerendered
"); }); + + test("updating env force rerendering children", async () => { + class Parent extends Widget { + inlineTemplate = `
`; + widgets = { Child }; + } + class Child extends Widget { + inlineTemplate = `
`; + } + (env).someKey = "hey"; + const widget = new Parent(env); + await widget.mount(fixture); + expect(fixture.innerHTML).toBe("
hey
"); + await widget.updateEnv({ someKey: "rerendered" }); + await nextTick(); + expect(fixture.innerHTML).toBe("
rerendered
"); + }); });