?
This document uses PHP Chinese website manual Release
action 和 mutation 類似,區(qū)別在于:
action 不改變狀態(tài),只提交(commit) mutation。
action 可以包含任意異步操作。
讓我們注冊一個簡單的 action:
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
Action 處理函數(shù)接收一個上下文對象(context object),該對象提供了跟 store 實例相同的方法/屬性,因此你可以調(diào)用 context.commit
提交一個 mutation,或者通過 context.state
和 context.getters
訪問 state 和 getters。稍后我們會介紹 Modules,我們將看到為什么上下文對象 (context object) 不是 store 實例自身。
在實踐中,我們經(jīng)常用到 ES2015 參數(shù)解構(gòu) 來簡化代碼(特別是我們要多次調(diào)用 commit
的時候):
actions: { increment ({ commit }) { commit('increment') } }
使用 store.dispatch
方法觸發(fā) action。
store.dispatch('increment')
這看起來很蠢:如果我們想增加 count,為什么我們不直接調(diào)用 store.commit('increment')
?回想起mutation 必須是同步函數(shù) 了嗎?action 可以不是同步函數(shù)。我們可以在 action 回調(diào)函數(shù)中執(zhí)行 異步操作:
actions: { incrementAsync ({ commit }) { setTimeout(() => { commit('increment') }, 1000) } }
action 同樣支持 payload 格式和對象風(fēng)格的 dispatch:
// dispatch 傳入 payload store.dispatch('incrementAsync', { amount: 10 }) // dispatch 傳入一個對象 store.dispatch({ type: 'incrementAsync', amount: 10 })
日常生活行為中,更實際的例子是購物車結(jié)帳,涉及調(diào)用異步 API和分發(fā)多重 mutations:
actions: { checkout ({ commit, state }, payload) { // 把當(dāng)前購物車的商品備份起來 const savedCartItems = [...state.cart.added] // 發(fā)送結(jié)帳請求,并愉快地清空購物車 commit(types.CHECKOUT_REQUEST) // 購物 API 接收一個成功回調(diào)和一個失敗回調(diào) shop.buyProducts( products, // 成功操作 () => commit(types.CHECKOUT_SUCCESS), // 失敗操作 () => commit(types.CHECKOUT_FAILURE, savedCartItems) ) } }
注意,我們執(zhí)行的是一個異步操作的流程,并通過提交 action 來記錄其副作用(狀態(tài)變化)。
使用 this.$store.dispatch('xxx')
(需要根組件中注入 store
)在組件中分發(fā) action,使用 mapActions
工具函數(shù),映射組件方法到調(diào)用 store.dispatch
:
import { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'increment' // 映射 this.increment() 到 this.$store.dispatch('increment') ]), ...mapActions({ add: 'increment' // map this.add() to this.$store.dispatch('increment') }) } }
Action 通常是異步的,所以我們?nèi)绾沃酪粋€ action 何時完成?更重要的是,我們?nèi)绾谓M合多個 action 一起操作復(fù)雜的異步流程?
第一件事是知道 store.dispatch
返回『action 回調(diào)函數(shù)被觸發(fā)后的返回值』,所以你可以在 action 中返回一個 Promise 對象。
actions: { actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit('someMutation') resolve() }, 1000) }) } }
現(xiàn)在你可以這么做:
store.dispatch('actionA').then(() => { // ... })
然后在另一個 action :
actions: { // ... actionB ({ dispatch, commit }) { return dispatch('actionA').then(() => { commit('someOtherMutation') }) } }
最后,如果我們使用 async / await,很快落地的 JavaScript 特性,我們可以這樣組合我們的 action:
// 假定 getData() and getOtherData() 返回的是 Promise actions: { async actionA ({ commit }) { commit('gotData', await getData()) }, async actionB ({ dispatch, commit }) { await dispatch('actionA') // 等待 actionA 結(jié)束 commit('gotOtherData', await getOtherData()) } }
store.dispatch
可能會在不同模塊中,觸發(fā)多個 action 回調(diào)函數(shù)。在這種情況下,返回值是一個 Promise 對象,該對象在所有被觸發(fā)的回調(diào)都 resolve 之后自己再 resolve。