Forráskód Böngészése

Action before and after subscribers (#1115)

* allow action subscribers to specify before/after hooks (#1098)

Action subscribers are called before the action by default. This allows them to specify before and after subscribers where the after subscriber is called when the action resolves

* add test cases for the new before/after action subscribers (#1098)

make sure that the before subscriber is called before the action, while the after subscriber is called after it resolves

* Replace Promise initialization with shorter form (#1098)

* Update subscribeAction type declaration and add type tests (#1098)

Generalize subscribeAction's type declaration to accept both a function or an object and add type tests for that
Wael Al-Sallami 6 éve
szülő
commit
76818c1b42
4 módosított fájl, 85 hozzáadás és 7 törlés
  1. 12 3
      src/store.js
  2. 31 0
      test/unit/modules.spec.js
  3. 10 1
      types/index.d.ts
  4. 32 3
      types/test/index.ts

+ 12 - 3
src/store.js

@@ -129,11 +129,19 @@ export class Store {
       return
     }
 
-    this._actionSubscribers.forEach(sub => sub(action, this.state))
+    this._actionSubscribers
+      .filter(sub => sub.before)
+      .forEach(sub => sub.before(action, this.state))
 
-    return entry.length > 1
+    const result = entry.length > 1
       ? Promise.all(entry.map(handler => handler(payload)))
       : entry[0](payload)
+
+    result.then(() => this._actionSubscribers
+      .filter(sub => sub.after)
+      .forEach(sub => sub.after(action, this.state)))
+
+    return result
   }
 
   subscribe (fn) {
@@ -141,7 +149,8 @@ export class Store {
   }
 
   subscribeAction (fn) {
-    return genericSubscribe(fn, this._actionSubscribers)
+    const subs = typeof fn === 'function' ? { before: fn } : fn
+    return genericSubscribe(subs, this._actionSubscribers)
   }
 
   watch (getter, cb, options) {

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

@@ -668,6 +668,37 @@ describe('Modules', () => {
         store.state
       )
     })
+
+    it('action before/after subscribers', (done) => {
+      const beforeSpy = jasmine.createSpy()
+      const afterSpy = jasmine.createSpy()
+      const store = new Vuex.Store({
+        actions: {
+          [TEST]: () => Promise.resolve()
+        },
+        plugins: [
+          store => {
+            store.subscribeAction({
+              before: beforeSpy,
+              after: afterSpy
+            })
+          }
+        ]
+      })
+      store.dispatch(TEST, 2)
+      expect(beforeSpy).toHaveBeenCalledWith(
+        { type: TEST, payload: 2 },
+        store.state
+      )
+      expect(afterSpy).not.toHaveBeenCalled()
+      Vue.nextTick(() => {
+        expect(afterSpy).toHaveBeenCalledWith(
+          { type: TEST, payload: 2 },
+          store.state
+        )
+        done()
+      })
+    })
   })
 
   it('asserts a mutation should be a function', () => {

+ 10 - 1
types/index.d.ts

@@ -19,7 +19,7 @@ export declare class Store<S> {
   commit: Commit;
 
   subscribe<P extends MutationPayload>(fn: (mutation: P, state: S) => any): () => void;
-  subscribeAction<P extends ActionPayload>(fn: (action: P, state: S) => any): () => void;
+  subscribeAction<P extends ActionPayload>(fn: SubscribeActionOptions<P, S>): () => void;
   watch<T>(getter: (state: S, getters: any) => T, cb: (value: T, oldValue: T) => void, options?: WatchOptions): () => void;
 
   registerModule<T>(path: string, module: Module<T, S>, options?: ModuleOptions): void;
@@ -69,6 +69,15 @@ export interface ActionPayload extends Payload {
   payload: any;
 }
 
+export type ActionSubscriber<P, S> = (action: P, state: S) => any;
+
+export interface ActionSubscribersObject<P, S> {
+  before?: ActionSubscriber<P, S>;
+  after?: ActionSubscriber<P, S>;
+}
+
+export type SubscribeActionOptions<P, S> = ActionSubscriber<P, S> | ActionSubscribersObject<P, S>;
+
 export interface DispatchOptions {
   root?: boolean;
 }

+ 32 - 3
types/test/index.ts

@@ -39,12 +39,41 @@ namespace StoreInstance {
     state.value;
   });
 
-  store.subscribeAction((mutation, state) => {
-    mutation.type;
-    mutation.payload;
+  store.subscribeAction((action, state) => {
+    action.type;
+    action.payload;
     state.value;
   });
 
+  store.subscribeAction({
+    before(action, state) {
+      action.type;
+      action.payload;
+      state.value;
+    }
+  });
+
+  store.subscribeAction({
+    before(action, state) {
+      action.type;
+      action.payload;
+      state.value;
+    },
+    after(action, state) {
+      action.type;
+      action.payload;
+      state.value;
+    }
+  });
+
+  store.subscribeAction({
+    after(action, state) {
+      action.type;
+      action.payload;
+      state.value;
+    }
+  });
+
   store.replaceState({ value: 10 });
 }