命名语义化
首先就是针对命名的语义化,主要集中在两个名词上:commit
与 dispatch
。
之前的 store.dispatch
变成了现在的 store.commit
,但是 store.dispatch
依然可用,但仅仅用来触发某些 action
。
首先,尤大认为用 dispatch
来使一个 mutation
发生改变在语义上是不正确的,dispatch
应当用来表明一个事件是我们有意触发的这样一个操作,但对于 mutation
来说,需要有一个动词来表示我们在做这个操作之后会触发状态改变,用他的原话来说就是:Dispatch should be indicating the intention for something to happen. For mutations, we want a verb that indicates the state change is happening as soon as you call it.
dispatch
:表明有某些事件发生的意向(可能是异步操作产生的副作用)。commit
:说明会使实际状态发生改变的同步操作。
例子:
// before 2.0.0 actions: { 'ACTION_TYPE': ({dispatch}, payload) => { dispatch(payload) } } // now actions: { 'ACTION_TYPE': ({ commit }, payload) => { commit('some-mutation', payload) } // dispatch store.dispatch('ACTION_TYPE')
从上面的代码中我们可以看出,在 vuex
2.0.0 中,commit
用来说明一个使 mutation
状态发生改变的操作,而 dispatch
则用来触发一个 action
。
模块的可移植性和可组合性
store
和 module
中的 action
如果我们在模块内部定义 actions
时,如果多个模块定义相同名字的 action
时可能会产生部分问题,而且有的时候需要调用多个模块的 action
,那么在这两种情况看来,如果我们把 action
定义为一个类似事件监听器的模式而不是直接调用它们,取而代之的是用 store.dispatch
去触发这个事件,这样的话我们就可以在一次调用中触发多个模块的 action
,而且这种做法也能够明确的表明这个 action
所有可能产生的副作用。
例子:
const store = new Vuex.Store({ actions: { doSomething: ({ commit }) => { commit('some-mutation') } } }) // 你可以直接访问这个action console.log(store.actions.doSomething) // 触发这个action store.dispatch('doSomething')
与之类似的还有 getters
我们同样可以直接在 store
中定义,也可以在 module
内部定义
例子:
const store = new Vuex.Store({ state: { count: 0 }, getters: { hasAny: state => state.count > 0 } }) // access the getter store.getters.hasAny // -> false
事件流可组合
因为 dispatch
的存在,我们在需要一次操作触发多个 action
的情况下,那么事件流的可组合就会使得代码写起来游刃有余,尤其是结合 Promise
或者 async/await
。比如我们有一个列表,在删除列表中的一项或多项之后,我们通常需要重新拉去一次列表或者将本地的列表数据重排,那么我们就可以在完成 deleteItem
之后通过 store.dispatch
来触发 getList
操作,与之形成对比的是,我们在 Redux
中所使用的 redux-saga
。
例子:
const store = new Vuex.Store({ actions: { deleteItem: ({ commit }, payload) => { return callPromiseAPI(payload).then(res => { commit('delete', { res }) }) }, getList: ({ commit }, payload) => { return callPromiseAPI(payload).then(res => { commit('list', { res }) }) } } }) store.dispatch('deleteItem', { id: 1 }).then(() => { // action done store.dispatch(getList, {page: 1}) })
// 结合 async/await const store = new Vuex.Store({ actions: { one: async ({ commit }, payload) => { const res = await callPromiseAPI(payload) commit('some-mutation', { res }) }, two: async ({ dispatch, commit }) => { await dispatch('one') commit('done') } } }) store.dispatch('two') // fires off complicated async flow
从上面的两部分代码你可能发现了两种写法,实际上两种写法的效果是一样的,只是 Promise.then()
与 async/await
的区别
其他
出上面两个之外,Vuex@2
还提供了 mapGetters
和 mapActions
两个辅助函数,在之前的版本中,我们在一个组件内部使用 getters
和 actions
通常都是通过下面种方式:
export default { vuex: { getters: { }, actions: { } } }
那么在有这两个辅助函数之后我们只需要这样:
import {mapActions, mapGetters} from 'vuex' export default { computed: mapGetters(['a', 'b', 'c']), methods: mapActions(['doA', 'doB', 'doC']) }
当然就像我们在第二部分中提到的,你可以通过下面中方式
export default { computed: { a: () { return this.$store.getters.a } }, methods: { doB: () { this.$store.dispatch('b') } } }
更多使用方法,请查看这个issue
文章均采用 CC BY-NC-SA 3.0 许可协议,转载请注明出处。