?
このドキュメントでは、 php中國(guó)語(yǔ)ネットマニュアル リリース
在 Vuex store 中,實(shí)際改變 狀態(tài)(state) 的唯一方式是通過(guò) 提交(commit) 一個(gè) mutation。 Vuex 的 mutation 和事件系統(tǒng)非常相似:每個(gè) mutation 都有一個(gè)字符串 類型(type) 和 一個(gè) 回調(diào)函數(shù)(handler)。回調(diào)函數(shù)是我們執(zhí)行實(shí)際修改狀態(tài)的地方,它將接收 狀態(tài)(state) 作為第一個(gè)參數(shù)。
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 改變 state state.count++ } } })
你不能直接調(diào)用 mutation 的回調(diào)函數(shù)。選項(xiàng) mutations 在這里更像是注冊(cè)事件:“當(dāng)觸發(fā)類型為 increment
的 mutation 時(shí),執(zhí)行其回調(diào)函數(shù)。”所以你需要調(diào)用該類型的 store.commit 才能執(zhí)行 mutation 的回調(diào)函數(shù)。
store.commit('increment')
向 store.commit
傳遞一個(gè)額外的參數(shù),這個(gè)參數(shù)被稱為 payload :
// ... mutations: { increment (state, n) { state.count += n } }
多數(shù)情況下,payload 應(yīng)該是一個(gè)對(duì)象,以便它可以包含多個(gè)字段,這樣 mutation 記錄中有了 payload 字段名,可描述性會(huì)變得更好。
// ... mutations: { increment (state, payload) { state.count += payload.amount } }
store.commit('increment', { amount: 10 })
提交 mutation 的另一種替代方式,是直接使用具有 type
屬性的對(duì)象:
store.commit({ type: 'increment', amount: 10 })
當(dāng)使用對(duì)象風(fēng)格的 commit,整個(gè)對(duì)象都會(huì)被作為 payload 參數(shù)傳入到對(duì)應(yīng)類型的 mutation 的回調(diào)函數(shù)中,不過(guò)回調(diào)函數(shù)還保持不變:
mutations: { increment (state, payload) { state.count += payload.amount } }
注意:一旦我們實(shí)現(xiàn)了 devtools 中過(guò)濾 mutation,此特性可能會(huì)被棄用。
默認(rèn)情況下,每個(gè)提交過(guò)的 mutation 都會(huì)被發(fā)送到插件(如 devtools)。然而在某些情況下,你可能不希望插件去記錄每個(gè)狀態(tài)更改。像是在短時(shí)間多次提交到 store 或輪詢,并不總是需要跟蹤。在這種情況下你可以在 store.commit
中傳入第三個(gè)參數(shù),來(lái)指定插件中的 mutation 是否“靜默”。
store.commit('increment', { amount: 1 }, { silent: true }) // 使用對(duì)象風(fēng)格的 dispatch store.commit({ type: 'increment', amount: 1 }, { silent: true })
由于 Vue 中 Vuex store 的狀態(tài)是響應(yīng)式的,當(dāng)我們改變狀態(tài),Vue 組件觀察到狀態(tài)改變將自動(dòng)更新。這也意味著 Vuex mutation 同樣遵循純 Vue 響應(yīng)式規(guī)則。
推薦預(yù)先初始化 store 中你所需的初始狀態(tài)。
向?qū)ο筇砑有碌膶傩詴r(shí),你應(yīng)該這樣做:
使用 Vue.set(obj, 'newProp', 123)
用新的對(duì)象替換該對(duì)象。例如,使用 stage-2 對(duì)象擴(kuò)展語(yǔ)法 我們可以這樣寫(xiě):
state.obj = { ...state.obj, newProp: 123
在各種 Flux 實(shí)現(xiàn)中,使用常量作為 mutation 類型是一種常見(jiàn)的模式。這允許代碼利用工具如 linters,將所有常量放在一個(gè)單獨(dú)文件中,盡可能使協(xié)作者對(duì)整個(gè)應(yīng)用的 mutation 一目了然。
// mutation-types.js export const SOME_MUTATION = 'SOME_MUTATION'
// store.js import Vuex from 'vuex' import { SOME_MUTATION } from './mutation-types' const store = new Vuex.Store({ state: { ... }, mutations: { // 我們能夠通過(guò)使用“ES2015 屬性名表達(dá)式”功能,來(lái)使用常量作為函數(shù)名稱 [SOME_MUTATION] (state) { // 改變狀態(tài) } } })
是否使用常量在很大程度上是一個(gè)偏好 - 在多人合作開(kāi)發(fā)的大型項(xiàng)目中它很有用,但如果你不喜歡使用,它也是完全可選的。
一個(gè)重要的原則就是牢記 mutation 必須是同步函數(shù)。為什么?考慮下面的例子:
mutations: { someMutation (state) { api.callAsyncMethod(() => { state.count++ }) } }
現(xiàn)在想象我們正在調(diào)試應(yīng)用程序,并查看 devtool 的 mutation 記錄。每個(gè) mutation 記錄,devtool 將需要捕獲每個(gè)狀態(tài)“之前”和“之后”的快照。然而,上面的示例中 mutation 內(nèi)部的異步回調(diào)使得這是不可能的:當(dāng) mutation 被提交后,回調(diào)函數(shù)還未被調(diào)用,也沒(méi)有辦法讓 devtool 知道回調(diào)函數(shù)在何時(shí)被調(diào)用 - 即在回調(diào)函數(shù)中執(zhí)行任意狀態(tài)變更,實(shí)際上都無(wú)法跟蹤。
可以在組件中使用 this.$store.commit('xxx')
提交 mutation,或者使用 mapMutations
工具遍歷組件方法到 store.commit
的回調(diào)上(需要把 store
注入根組件)
import { mapMutations } from 'vuex' export default { // ... methods: { ...mapMutations([ 'increment' // 映射 this.increment() 到 this.$store.commit('increment') ]), ...mapMutations({ add: 'increment' // 映射 this.add() 到 this.$store.commit('increment') }) } }
在 mutation 中混合異步調(diào)用會(huì)導(dǎo)致你的程序很難調(diào)試。例如當(dāng)你調(diào)用兩個(gè)都含有異步回調(diào)的方法去改變狀態(tài),你如何知道他們何時(shí)被調(diào)用和哪個(gè)回調(diào)被首先調(diào)用?這正是我們分離 Mutation 和 Action 這兩個(gè)概念的原因。在 Vuex,Mutation 必須是同步事務(wù):
store.commit('increment') // 類型為 "increment" 的 mutation 提交后,可能引起的任意狀態(tài)變化,都應(yīng)該在此時(shí)同步完成
為了處理異步操作,接下來(lái)我們介紹 Actions。