diff --git a/src/store.ts b/src/store.ts index 6571d358..289e99e1 100644 --- a/src/store.ts +++ b/src/store.ts @@ -96,14 +96,11 @@ export function useStore(selector, options: SelectorOptions = {}): any { if (!store.updateFunctions[componentId]) { store.updateFunctions[componentId] = []; } - store.updateFunctions[componentId].push(function(): boolean { + function selectCompareUpdate(state, props): boolean { const oldResult = result; - result = selector(store!.state, component.props); + result = selector(state, props); const newRevNumber = hashFn(result); - if ( - (newRevNumber > 0 && revNumber !== newRevNumber) || - (newRevNumber === 0 && !isEqual(oldResult, result)) - ) { + if ((newRevNumber > 0 && revNumber !== newRevNumber) || !isEqual(oldResult, result)) { revNumber = newRevNumber; if (options.onUpdate) { options.onUpdate(result); @@ -111,6 +108,9 @@ export function useStore(selector, options: SelectorOptions = {}): any { return true; } return false; + } + store.updateFunctions[componentId].push(function(): boolean { + return selectCompareUpdate(store!.state, component.props); }); useContextWithCB(store, component, function(): Promise | void { @@ -123,7 +123,7 @@ export function useStore(selector, options: SelectorOptions = {}): any { } }); onWillUpdateProps(props => { - result = selector(store.state, props); + selectCompareUpdate(store.state, props); }); const __destroy = component.__destroy; diff --git a/tests/store_hooks.test.ts b/tests/store_hooks.test.ts index 262ca3b5..b8684289 100644 --- a/tests/store_hooks.test.ts +++ b/tests/store_hooks.test.ts @@ -490,6 +490,49 @@ describe("connecting a component to store", () => { expect(fixture.innerHTML).toBe("
jupilerkwak
"); }); + test("connected component is updated when mixing store and props changes", async () => { + let counter = 0; + + class Beer extends Component { + static template = xml``; + beer = useStore((state, props) => state.beers[props.id], { + onUpdate: result => { + ++counter; + } + }); + } + + class App extends Component { + static template = xml`
`; + static components = { Beer }; + state = useState({ beerId: 1 }); + } + + const state = { beers: { 1: { name: "jupiler" }, 2: { name: "kwak" } } }; + const actions = { + renameBeer({ state }, { id, name }) { + state.beers[id].name = name; + } + }; + const store = new Store({ state, actions }); + (env).store = store; + const app = new App(); + + await app.mount(fixture); + expect(fixture.innerHTML).toBe("
jupiler
"); + expect(counter).toBe(0); + + app.state.beerId = 2; + await nextTick(); + expect(fixture.innerHTML).toBe("
kwak
"); + expect(counter).toBe(1); + + store.dispatch("renameBeer", { id: 2, name: "orval" }); + await nextTick(); + expect(fixture.innerHTML).toBe("
orval
"); + expect(counter).toBe(2); + }); + test("connected component is properly cleaned up on destroy", async () => { class App extends Component { static template = xml`
`;