Skip to content

Commit

Permalink
Action before and after subscribers (#1115)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Wael Al-Sallami authored and yyx990803 committed Jan 4, 2019
1 parent da22a6e commit 76818c1
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 7 deletions.
15 changes: 12 additions & 3 deletions src/store.js
Expand Up @@ -129,19 +129,28 @@ 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) {
return genericSubscribe(fn, this._subscribers)
}

subscribeAction (fn) {
return genericSubscribe(fn, this._actionSubscribers)
const subs = typeof fn === 'function' ? { before: fn } : fn
return genericSubscribe(subs, this._actionSubscribers)
}

watch (getter, cb, options) {
Expand Down
31 changes: 31 additions & 0 deletions test/unit/modules.spec.js
Expand Up @@ -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', () => {
Expand Down
11 changes: 10 additions & 1 deletion types/index.d.ts
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
35 changes: 32 additions & 3 deletions types/test/index.ts
Expand Up @@ -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 });
}

Expand Down

0 comments on commit 76818c1

Please sign in to comment.