diff --git a/src/store/connected_component.ts b/src/store/connected_component.ts index 8033fc3f..72c187ca 100644 --- a/src/store/connected_component.ts +++ b/src/store/connected_component.ts @@ -12,19 +12,20 @@ export class ConnectedComponent extends Component return env.store; } - hashFunction: HashFunction = ({ storeProps }, options) => { - const observer = (this.__owl__ as any).store.observer; - let refFunction = this.deep ? observer.deepRevNumber : observer.revNumber; - if ("__owl__" in storeProps) { - return refFunction.call(observer, storeProps); + storeProps: any; + + hashFunction: HashFunction = (storeProps, options) => { + const revFn = (this.__owl__ as any).revFn; + const rev = revFn(storeProps); + if (rev > 0) { + return rev; } - const { currentStoreProps } = options; let hash = 0; for (let key in storeProps) { const val = storeProps[key]; - const hashVal = refFunction.call(observer, val); + const hashVal = revFn(val); if (hashVal === 0) { - if (val !== currentStoreProps[key]) { + if (val !== options.prevStoreProps[key]) { options.didChange = true; } } else { @@ -37,32 +38,23 @@ export class ConnectedComponent extends Component static mapStoreToProps(storeState, ownProps, getters) { return {}; } - constructor(parent, props?: any) { - super(parent, props); + /** + * Need to do this here so 'deep' can be overrided by subcomponent easily + */ + async __prepareAndRender(scope?: Object, vars?: any): ReturnType["__prepareAndRender"]> { const store = this.getStore(this.env); const ownProps = this.props || {}; - const storeProps = (this.constructor).mapStoreToProps( - store.state, - ownProps, - store.getters - ); - const mergedProps = Object.assign({}, ownProps, storeProps); - - this.props = mergedProps; - - (this.__owl__).ownProps = ownProps; - (this.__owl__).currentStoreProps = storeProps; - (this.__owl__).store = store; - (this.__owl__).storeHash = this.hashFunction( - { - state: store.state, - storeProps: storeProps - }, - { - currentStoreProps: storeProps - } - ); + this.storeProps = (this.constructor).mapStoreToProps(store.state, ownProps, store.getters); + const observer = store.observer; + const revFn = this.deep ? observer.deepRevNumber : observer.revNumber; + (this.__owl__ as any).store = store; + (this.__owl__ as any).revFn = revFn.bind(observer); + (this.__owl__ as any).storeHash = this.hashFunction(this.storeProps, { + prevStoreProps: this.storeProps + }); + (this.__owl__ as any).rev = observer.rev; + return super.__prepareAndRender(scope, vars); } /** * We do not use the mounted hook here for a subtle reason: we want the @@ -70,56 +62,47 @@ export class ConnectedComponent extends Component * if we use the mounted hook, this will be done in the reverse order. */ __callMounted() { - (this.__owl__).store.on("update", this, this.__checkUpdate); + (this.__owl__ as any).store.on("update", this, this.__checkUpdate); super.__callMounted(); } - willUnmount() { - (this.__owl__).store.off("update", this); - super.willUnmount(); + __callWillUnmount() { + (this.__owl__ as any).store.off("update", this); + super.__callWillUnmount(); } - async __checkUpdate(updateId) { - if (updateId === (this.__owl__).currentUpdateId) { - return; - } - const ownProps = (this.__owl__).ownProps; - const storeProps = (this.constructor).mapStoreToProps( - (this.__owl__).store.state, - ownProps, - (this.__owl__).store.getters - ); - const options: any = { - currentStoreProps: (this.__owl__).currentStoreProps - }; - const storeHash = this.hashFunction( - { - state: (this.__owl__).store.state, - storeProps: storeProps - }, - options - ); - let didChange = options.didChange; - if (storeHash !== (this.__owl__).storeHash) { - didChange = true; - (this.__owl__).storeHash = storeHash; - } - if (didChange) { - (this.__owl__).currentStoreProps = storeProps; - await this.__updateProps(ownProps, false); - } + async __updateProps(nextProps: P, f, p, s, v) { + this.__updateStoreProps(nextProps); + return super.__updateProps(nextProps, f, p, s, v); } - __updateProps(nextProps, forceUpdate, patchQueue?: any[]) { - const __owl__ = this.__owl__; - __owl__.currentUpdateId = __owl__.store._updateId; - if (__owl__.ownProps !== nextProps) { - __owl__.currentStoreProps = (this.constructor).mapStoreToProps( - __owl__.store.state, - nextProps, - __owl__.store.getters - ); + + __updateStoreProps(nextProps): boolean { + const store = (this.__owl__ as any).store; + const storeProps = (this.constructor).mapStoreToProps( + store.state, + nextProps, + store.getters + ); + const options = { prevStoreProps: this.storeProps, didChange: false }; + const storeHash = this.hashFunction(storeProps, options); + this.storeProps = storeProps; + let didChange = options.didChange; + if (storeHash !== (this.__owl__ as any).storeHash) { + (this.__owl__ as any).storeHash = storeHash; + didChange = true; + } + (this.__owl__ as any).rev = store.observer.rev; + return didChange + } + + async __checkUpdate() { + const observer = (this.__owl__ as any).store.observer; + if (observer.rev === (this.__owl__ as any).rev) { + // update was already done by updateProps, from parent + return; + } + const didChange = this.__updateStoreProps(this.props); + if (didChange) { + this.render(); } - __owl__.ownProps = nextProps; - const mergedProps = Object.assign({}, nextProps, __owl__.currentStoreProps); - return super.__updateProps(mergedProps, forceUpdate, patchQueue); } } diff --git a/tests/store/connected_component.test.ts b/tests/store/connected_component.test.ts index dad0c20b..29b259bd 100644 --- a/tests/store/connected_component.test.ts +++ b/tests/store/connected_component.test.ts @@ -20,7 +20,7 @@ describe("connecting a component to store", () => { env.qweb.addTemplates(`
- +
@@ -56,7 +56,7 @@ describe("connecting a component to store", () => { env.qweb.addTemplates(`
- +
@@ -104,7 +104,7 @@ describe("connecting a component to store", () => { env.qweb.addTemplates(`
- +
@@ -196,9 +196,9 @@ describe("connecting a component to store", () => { env.qweb.addTemplates(` - +
- +
@@ -247,11 +247,11 @@ describe("connecting a component to store", () => { env.qweb.addTemplates(`
- - + +
- +
@@ -287,7 +287,7 @@ describe("connecting a component to store", () => { test("connected component is updated when props are updated", async () => { env.qweb.addTemplates(` - +
@@ -322,7 +322,7 @@ describe("connecting a component to store", () => { env.qweb.addTemplates(`
- +
`); @@ -357,9 +357,9 @@ describe("connecting a component to store", () => { env.qweb.addTemplates(`
- taster: - selected: - consumed: + taster: + selected: + consumed:
@@ -424,9 +424,9 @@ describe("connecting a component to store", () => { env.qweb.addTemplates(`
- taster: - selected: - consumed: + taster: + selected: + consumed:
@@ -517,9 +517,9 @@ describe("connecting a component to store", () => { env.qweb.addTemplates(`
- +
- +
`); @@ -577,13 +577,13 @@ describe("connecting a component to store", () => { env.qweb.addTemplates(`
- +
- +
@@ -656,13 +656,13 @@ describe("connecting a component to store", () => { env.qweb.addTemplates(`
- +
- +
@@ -720,7 +720,7 @@ describe("connecting a component to store", () => { env.qweb.addTemplates(` -
+
`); @@ -829,11 +829,11 @@ describe("connected components and default values", () => {
- +
- +