Pārlūkot izejas kodu

feat: preserve state with registerModule (#837)

Blake Newman 7 gadi atpakaļ
vecāks
revīzija
4c1841e79e
6 mainītis faili ar 39 papildinājumiem un 5 dzēšanām
  1. 3 1
      docs/en/api.md
  2. 2 0
      docs/en/modules.md
  3. 2 2
      src/store.js
  4. 22 0
      test/unit/modules.spec.js
  5. 6 2
      types/index.d.ts
  6. 4 0
      types/test/index.ts

+ 3 - 1
docs/en/api.md

@@ -156,10 +156,12 @@ const store = new Vuex.Store({ ...options })
 
   Most commonly used in plugins. [Details](plugins.md)
 
-- **`registerModule(path: string | Array<string>, module: Module)`**
+- **`registerModule(path: string | Array<string>, module: Module, options?: Object)`**
 
   Register a dynamic module. [Details](modules.md#dynamic-module-registration)
 
+  `options` can have `preserveState: true` that allows to preserve the previous state. Useful with Server Side Rendering.
+
 - **`unregisterModule(path: string | Array<string>)`**
 
   Unregister a dynamic module. [Details](modules.md#dynamic-module-registration)

+ 2 - 0
docs/en/modules.md

@@ -269,6 +269,8 @@ Dynamic module registration makes it possible for other Vue plugins to also leve
 
 You can also remove a dynamically registered module with `store.unregisterModule(moduleName)`. Note you cannot remove static modules (declared at store creation) with this method.
 
+It may be likely that you want to preserve the previous state when registering a new module, such as preserving state from a Server Side Rendered app. You can do achieve this with `preserveState` option: `store.registerModule('a', module, { preserveState: true })`
+
 ### Module Reuse
 
 Sometimes we may need to create multiple instances of a module, for example:

+ 2 - 2
src/store.js

@@ -161,7 +161,7 @@ export class Store {
     })
   }
 
-  registerModule (path, rawModule) {
+  registerModule (path, rawModule, options = {}) {
     if (typeof path === 'string') path = [path]
 
     if (process.env.NODE_ENV !== 'production') {
@@ -170,7 +170,7 @@ export class Store {
     }
 
     this._modules.register(path, rawModule)
-    installModule(this, this.state, path, this._modules.get(path))
+    installModule(this, this.state, path, this._modules.get(path), options.preserveState)
     // reset store to update getters...
     resetStoreVM(this, this.state)
   }

+ 22 - 0
test/unit/modules.spec.js

@@ -80,6 +80,28 @@ describe('Modules', () => {
       store.commit('a/foo')
       expect(mutationSpy).toHaveBeenCalled()
     })
+
+    it('dynamic module registration preserving hydration', () => {
+      const store = new Vuex.Store({})
+      store.replaceState({ a: { foo: 'state' }})
+      const actionSpy = jasmine.createSpy()
+      const mutationSpy = jasmine.createSpy()
+      store.registerModule('a', {
+        namespaced: true,
+        getters: { foo: state => state.foo },
+        actions: { foo: actionSpy },
+        mutations: { foo: mutationSpy }
+      }, { preserveState: true })
+
+      expect(store.state.a.foo).toBe('state')
+      expect(store.getters['a/foo']).toBe('state')
+
+      store.dispatch('a/foo')
+      expect(actionSpy).toHaveBeenCalled()
+
+      store.commit('a/foo')
+      expect(mutationSpy).toHaveBeenCalled()
+    })
   })
 
   // #524

+ 6 - 2
types/index.d.ts

@@ -20,8 +20,8 @@ export declare class Store<S> {
   subscribe<P extends MutationPayload>(fn: (mutation: P, state: S) => any): () => void;
   watch<T>(getter: (state: S) => T, cb: (value: T, oldValue: T) => void, options?: WatchOptions): () => void;
 
-  registerModule<T>(path: string, module: Module<T, S>): void;
-  registerModule<T>(path: string[], module: Module<T, S>): void;
+  registerModule<T>(path: string, module: Module<T, S>, options?: ModuleOptions): void;
+  registerModule<T>(path: string[], module: Module<T, S>, options?: ModuleOptions): void;
 
   unregisterModule(path: string): void;
   unregisterModule(path: string[]): void;
@@ -96,6 +96,10 @@ export interface Module<S, R> {
   modules?: ModuleTree<R>;
 }
 
+export interface ModuleOptions{
+  preserveState?: boolean
+}
+
 export interface GetterTree<S, R> {
   [key: string]: Getter<S, R>;
 }

+ 4 - 0
types/test/index.ts

@@ -200,6 +200,10 @@ namespace RegisterModule {
     state: { value: 2 }
   });
 
+  store.registerModule(["a", "b"], {
+    state: { value: 2 }
+  }, { preserveState: true });
+
   store.unregisterModule(["a", "b"]);
   store.unregisterModule("a");
 }