From 1f079b883ebe0c595bd9960d50271d5b598e17a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Tue, 26 Nov 2019 22:51:35 +0100 Subject: [PATCH] [IMP] store: prevent changes to store state in useStore return value closes #500 --- doc/reference/store.md | 3 +++ src/store.ts | 3 +-- tests/store_hooks.test.ts | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/doc/reference/store.md b/doc/reference/store.md index b35d6af1..aef98896 100644 --- a/doc/reference/store.md +++ b/doc/reference/store.md @@ -274,6 +274,9 @@ Note that if the selector function returns a primitive type, the result of is important to define the `onUpdate` option to properly update the value manually when it changes. +Also, the return value from `useStore` is not supposed to be modified. The store +state should only be updated with actions. + ### `useDispatch` The `useDispatch` hook is useful when a component needs to be able to dispatch diff --git a/src/store.ts b/src/store.ts index 3a07c77d..5a469b03 100644 --- a/src/store.ts +++ b/src/store.ts @@ -134,8 +134,7 @@ export function useStore(selector, options: SelectorOptions = {}): any { return result[k]; }, set(target, k, v) { - result[k] = v; - return true; + throw new Error("Store state should only be modified through actions"); } }); } diff --git a/tests/store_hooks.test.ts b/tests/store_hooks.test.ts index d181d2f0..73360be6 100644 --- a/tests/store_hooks.test.ts +++ b/tests/store_hooks.test.ts @@ -100,6 +100,24 @@ describe("connecting a component to store", () => { expect(error.message).toBe("No store found when connecting 'App'"); }); + test("cannot modify state returned by usestore", async () => { + const state = { a: { b: 1 } }; + const actions = {}; + const store = new Store({ state, actions }); + + class App extends Component { + static template = xml`
`; + storeState = useStore(state => state.a); + } + + (env).store = store; + const app = new App(); + expect(app.storeState.b).toBe(1); + expect(() => (app.storeState.b = 2)).toThrow( + "Store state should only be modified through actions" + ); + }); + test("can use useStore twice in a component", async () => { const state = { a: 1, b: 2 }; const actions = {