diff --git a/web/static/src/ts/core/Widget.ts b/web/static/src/ts/core/Widget.ts index da77c362..eb99ab3e 100644 --- a/web/static/src/ts/core/Widget.ts +++ b/web/static/src/ts/core/Widget.ts @@ -83,7 +83,9 @@ export class Widget { mounted() {} - propsUpdated(newProps: any) {} + shouldUpdate(nextProps: any): boolean { + return true; + } willUnmount() {} @@ -138,16 +140,17 @@ export class Widget { * Note: it is ok to call updateState before the widget is started. In that * case, it will simply update the state and will not rerender */ - async updateState(newState: Object) { - Object.assign(this.state, newState); + async updateState(nextState: Object) { + Object.assign(this.state, nextState); if (this.__widget__.isStarted) { await this.render(); } } - updateProps(props?: any): Promise { - this.props = props; - return this.render(); + updateProps(nextProps?: any): Promise { + const shouldUpdate = this.shouldUpdate(nextProps); + this.props = nextProps; + return shouldUpdate ? this.render() : Promise.resolve(); } //-------------------------------------------------------------------------- diff --git a/web/static/tests/core/widget.test.ts b/web/static/tests/core/widget.test.ts index a7a9fc5f..66708366 100644 --- a/web/static/tests/core/widget.test.ts +++ b/web/static/tests/core/widget.test.ts @@ -372,6 +372,25 @@ describe("lifecycle hooks", () => { "p destroyed" ]); }); + + test("shouldUpdate hook prevent rerendering", async () => { + let shouldUpdate = false; + class TestWidget extends Widget { + name = "a"; + template = `
`; + shouldUpdate() { + return shouldUpdate; + } + } + const widget = new TestWidget(env, { val: 42 }); + await widget.mount(fixture); + expect(fixture.innerHTML).toBe("
42
"); + await widget.updateProps({ val: 123 }); + expect(fixture.innerHTML).toBe("
42
"); + shouldUpdate = true; + await widget.updateProps({ val: 666 }); + expect(fixture.innerHTML).toBe("
666
"); + }); }); describe("destroy method", () => {