Mutation
更改Vuex的store中的狀態(tài)的唯一方法是提交mutation。Vuex中的mutation非常類似于事件:每個mutation都有一個字符串的事件類型(type)和一個回調(diào)函數(shù)(handler)。這個回調(diào)函數(shù)就是我們實際進行狀態(tài)更改的地方,并且它會接受state作為第一個參數(shù)。
const store=new Vuex.Store({
state:{
count:1
},
mutations:{
increment(state){
//變更狀態(tài)
state.count++
}
}
})
不能直接調(diào)用一個mutation handler。這個選項更像是事件注冊:“當觸發(fā)一個類型為increment的mutation時,調(diào)用此函數(shù)?!币獑拘岩粋€mutation handler,你需要以相應(yīng)的type調(diào)用store.commit方法:
store.commit('increment')
提交載荷(Payload)
可以向store.commit 傳入額外的參數(shù),即mutation的載荷(payload):
//...
mutations:{
increment(state,n){
state.count+=n
}
}
store.commit('increment',10)
在大多數(shù)情況下,載荷應(yīng)該是一個對象,這樣可以包含多個字段并且記錄的mutation會更易讀:
mutations:{
increment(state,payload){
state.count+=payload.amount
}
}
store.commit('increment',{amount:10})
對象風格的提交方式
提交mutation的另一種方式是直接使用包含type屬性的對象:
store.commit({
type:'increment',
amount:10
})
當使用對象風格的提交方式,整個對象都作為載荷傳給mutation函數(shù),因此handler保持不變:
mutations:{
increment(state,payload){
state.count += payload.amount
}
}
Mutation 需遵守Vue的響應(yīng)規(guī)則
既然Vuex 的store中的狀態(tài)是響應(yīng)式的,那么當我們變更狀態(tài)時,監(jiān)視狀態(tài)的Vue組件也會自動更新。這意味著Vuex中的mutation也需要與使用Vue一樣遵守一些注意事項:
1.最好提前在你的store中初始化好所有所需屬性。
2.當需要在對象上添加新屬性時,你應(yīng)該:
- 使用Vue.set(obj,'newProp',123),或者
- 以新對象替換老對象。例如,利用stage-3的對象展開運算符我們可以這樣寫:
state.obj={...state.obj,nerProp:123}
使用常量替代Mutation事件類型
使用常量替代mutation事件類型在各種Flux(流量,流出)實現(xiàn)中是很常見的模式。這樣可以使linter(代碼檢查工具)之類的工具發(fā)揮作用,同時把這些常量放在單獨的文件中可以讓你的代碼合作者對整個app包含的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:{
//我們可以使用ES2015風格的計算屬性命名功能來使用一個常量作為函數(shù)名
[SOME_MUTATION](state){
//mutate state
}
}
})
使用或不使用常量取決于你——在需要多人協(xié)作的大型項目中,這會有幫助。但如果你不喜歡,你完全可以不這樣做。
Mutation必須是同步函數(shù)
一條重要原則就是要記住mutation必須是同步函數(shù)。
mutations:{
someMutation(state){
api.callAsyncMethod(()=>{
state.count++
})
}
}
現(xiàn)在想象,我們正在debug一個app并且觀察devtool中的mutation日志。每一條mutation被記錄,devtools都需要捕捉到前一狀態(tài)和后一狀態(tài)的快照。然而,在上面的例子中mutation中的異步函數(shù)中的回調(diào)讓這不可能完成:因為當mutation觸發(fā)的時候,回調(diào)函數(shù)還沒有被調(diào)用,devtools不知道什么時候回調(diào)函數(shù)實際上被調(diào)用——實質(zhì)上任何在回調(diào)函數(shù)中進行的狀態(tài)的改變都是不可追蹤的。
在組件中提交Mutation
你可以在組件中使用this.$store.commit('xxx')提交mutation,或者使用mapMutations輔助函數(shù)將組件中的methods映射為store.commitd調(diào)用(需要在根節(jié)點注入store)。
import {mapMutations} from 'vuex'
export default {
//...
methods:{
...mapMutations([
'increment',//將'this.increment()'映為‘this.$store.commint('increment')’
//mapMutations也支持載荷:
'incrementBy' //將‘this.incrementBy(amount)’映射為‘this.$store.commit('incremenrBY',amount)’
]),
...mapMutations({
add:'increment' //將'this.add()'映射為‘this.$store.commit('increment')’
})
}
}
下一步:Action
在mutation中混合異步調(diào)用會導(dǎo)致你的程序很難調(diào)試。例如,當你能調(diào)用了兩個包含異步回調(diào)的mutation來改變狀態(tài),你怎么知道什么時候回調(diào)和哪個先回調(diào)呢?這就是為什么我們要區(qū)分兩個概念。在vuex中,mutation都是同步事務(wù):
store.commit('increment')
//任何由“increment”導(dǎo)致的狀態(tài)變更都應(yīng)該在此刻完成。
為了處理異步操作,讓我們來看一看Action。
本文來源vuex官網(wǎng)