Skip to content

Commit

Permalink
feat: subscribeAction
Browse files Browse the repository at this point in the history
Allows to listen dispatched actions
  • Loading branch information
deini committed Sep 19, 2017
1 parent 7d9730e commit bba1271
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 11 deletions.
32 changes: 22 additions & 10 deletions src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export class Store {
// store internal state
this._committing = false
this._actions = Object.create(null)
this._actionSubscribers = []
this._mutations = Object.create(null)
this._wrappedGetters = Object.create(null)
this._modules = new ModuleCollection(options)
Expand Down Expand Up @@ -123,29 +124,28 @@ export class Store {
payload
} = unifyObjectStyle(_type, _payload)

const action = { type, payload }
const entry = this._actions[type]
if (!entry) {
if (process.env.NODE_ENV !== 'production') {
console.error(`[vuex] unknown action type: ${type}`)
}
return
}

this._actionSubscribers.forEach(sub => sub(action, this.state))

return entry.length > 1
? Promise.all(entry.map(handler => handler(payload)))
: entry[0](payload)
}

subscribe (fn) {
const subs = this._subscribers
if (subs.indexOf(fn) < 0) {
subs.push(fn)
}
return () => {
const i = subs.indexOf(fn)
if (i > -1) {
subs.splice(i, 1)
}
}
return genericSubscribe(fn, this._subscribers)
}

subscribeAction (fn) {
return genericSubscribe(fn, this._actionSubscribers)
}

watch (getter, cb, options) {
Expand Down Expand Up @@ -203,6 +203,18 @@ export class Store {
}
}

function genericSubscribe(fn, subs) {
if (subs.indexOf(fn) < 0) {
subs.push(fn)
}
return () => {
const i = subs.indexOf(fn)
if (i > -1) {
subs.splice(i, 1)
}
}
}

function resetStore (store, hot) {
store._actions = Object.create(null)
store._mutations = Object.create(null)
Expand Down
14 changes: 13 additions & 1 deletion test/unit/modules.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,9 @@ describe('Modules', () => {

it('plugins', function () {
let initState
const actionSpy = jasmine.createSpy()
const mutations = []
const subscribeActionSpy = jasmine.createSpy()
const store = new Vuex.Store({
state: {
a: 1
Expand All @@ -563,21 +565,31 @@ describe('Modules', () => {
state.a += n
}
},
actions: {
[TEST]: actionSpy
},
plugins: [
store => {
initState = store.state
store.subscribe((mut, state) => {
expect(state).toBe(store.state)
expect(state).toBe(state)
mutations.push(mut)
})
store.subscribeAction(subscribeActionSpy)
}
]
})
expect(initState).toBe(store.state)
store.commit(TEST, 2)
store.dispatch(TEST, 2)
expect(mutations.length).toBe(1)
expect(mutations[0].type).toBe(TEST)
expect(mutations[0].payload).toBe(2)
expect(actionSpy).toHaveBeenCalled()
expect(subscribeActionSpy).toHaveBeenCalledWith(
{ type: TEST, payload: 2 },
store.state
)
})
})

Expand Down
26 changes: 26 additions & 0 deletions test/unit/store.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,32 @@ describe('Store', () => {
expect(store.state.a).toBe(3)
})

it('subscribe: should handle subscriptions / unsubscriptions', () => {
const subscribeSpy = jasmine.createSpy()
const secondSubscribeSpy = jasmine.createSpy()
const testPayload = 2
const store = new Vuex.Store({
state: {},
mutations: {
[TEST]: () => {}
}
})

const unsubscribe = store.subscribe(subscribeSpy)
store.subscribe(secondSubscribeSpy)
store.commit(TEST, testPayload)
unsubscribe()
store.commit(TEST, testPayload)

expect(subscribeSpy).toHaveBeenCalledWith(
{ type: TEST, payload: testPayload },
store.state
)
expect(secondSubscribeSpy).toHaveBeenCalled()
expect(subscribeSpy.calls.count()).toBe(1)
expect(secondSubscribeSpy.calls.count()).toBe(2)
})

// store.watch should only be asserted in non-SSR environment
if (!isSSR) {
it('strict mode: warn mutations outside of handlers', () => {
Expand Down

0 comments on commit bba1271

Please sign in to comment.