vuex中store 的mutation
vuex中store 的mutation
1.mutation
官方解釋mutation:
更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation。Vuex 中的 mutation 非常類似於事件:每個 mutation 都有一個字串的 事件型別 (type) 和 一個 回撥函式 (handler)。這個回撥函式就是我們實際進行狀態更改的地方,並且它會接受 state 作為第一個引數
官方是建議我們通過mutation來實現更改store中的state的資料,而非在元件中直接使用
s
t
o
r
e
.
s
t
a
t
e
.
d
a
t
a
=
x
x
x
來
直
接
進
行
更
改
。
通
過
m
u
t
a
t
i
o
n
來
更
改
數
據
的
操
作
會
被
捕
獲
到
,
而
直
接
使
用
store.state.data=xxx來直接進行更改。通過mutation來更改資料的操作會被捕獲到,而直接使用
圖示:
上網找到 一個很不錯的圖
流程:
- 繞過Actions(mutation必須是同步操作,Devtools才能追蹤變數)
- 使用者觸發事件
- 在事件處理中通過commit()提交對應的mutation
- mutation中對state進行修改
- state修改後響應系統更新檢視
- 不繞過Actions(Action 可以包含任意非同步操作)
- 使用者觸發事件
- 在事件處理中通過dispatch()提交對應的Actions
- 在Actions中通過commit()提交對應的mutation
- mutation中對state進行修改
- state修改後響應系統更新檢視
解析:
當我們只有同步操作的時候,官方允許我們在元件中直接提交mutation,而不經過Actions,但是如果我們的操作包含非同步操作的時候,我們必須通過Actions來非同步提交mutation,從而實現非同步操作,這樣才能讓Devtools可以捕獲變數更改。
2.初次使用
const store = new Vuex. Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 變更狀態
state.count++
},
incrementNum (state,num) {
// 通過提交載荷傳遞過來的num
state.count+=num
}
}
})
//在元件中定義一個方法通過$store.commit('increment')來進行提交
methods:{
increment(){
this.$store.commit('increment')
},
incrementNum(num){
this.$store.commit('increment',num)
}
}
3.提交載荷
mutations接受commit傳遞過來的引數,這個引數叫做payload(提交載荷),我們可以通過payload來實現資料的傳遞。
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
store.commit('increment', {
amount: 10
})
4.物件風格的提交方式
store.commit()提供了另一種提交風格,store.commit()允許以物件的風格進行提交,這個風格跟vue很切合,物件宣告形式。
store.commit({
type: 'increment', //對應commit第一個引數,也就是事件型別
amount: 10 //傳遞的引數payload
})
使用
mutations: {
increment (state, payload) { //物件提交方式,payload是提交載荷
state.count += payload.amount
}
}
5.Mutation 需遵守 Vue 的響應規則
Vuex 的 store 中的狀態是響應式的,所以Vuex 中的 mutation 也需要與使用 Vue 一樣遵守一些注意事項。
新增操作
//錯誤的示範
state.info['address']='北京'
//正確的示範
Vue.set(state.info,'address','北京')
//vue官方說以新物件替換老物件是遵守 Vue 的響應規則
//響應系統能捕獲全新的物件資料
state.info = {//一個全新的物件}
第一個示範雖然是給state中的info添加了一個key value,但是這種新增操作是繞過了vue的響應式系統的,所以vue並沒有將新新增的key value追加到響應系統裡面,所以檢視是不會動態跟新新新增的資料。
而第二種示範,是通過vue的響應式系統進行變數的追加,所以vue能監控到變數的變化,從而對檢視做出響應和跟新。
刪除操作
刪除操作同理
Vue.delete(state.info,'address')
6.用常量替代Mutation事件型別
從上面的程式碼可以看出,我在使用store.commit的時候後面都是通過字串的形式來指定commit的mutation。而官方建議是將這種mutation 事件型別進行一個抽離,將這些mutation的名字定義到一個專門儲存的單獨檔案種,這樣做抽離,使得整個APP的mutatio易於管理,也使得專案結構清晰。
使用常量替代 mutation 事件型別在各種 Flux 實現中是很常見的模式。這樣可以使 linter 之類的工具發揮作用,同時把這些常量放在單獨的檔案中可以讓你的程式碼合作者對整個 app 包含的 mutation 一目瞭然:
官方建議的操作如下:
先將建立一個mutation-types.js,裡面儲存定義的mutation 事件型別
// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
//定義什麼mutation,先將事件型別(名字)寫這裡
使用的時候
// store.js
import Vuex from 'vuex'
import { SOME_MUTATION } from './mutation-types'
const store = new Vuex.Store({
state: { ... },
mutations: {
/*
官方是用這種風格來命名的:
[SOME_MUTATION] (state) {}
---等價轉變--->SOME_MUTATION(state) {}
*/
// 我們可以使用 ES2015 風格的計算屬性命名功能來使用一個常量作為函式名
[SOME_MUTATION] (state) {
// mutate state
}
}
})
//其他元件commit時
import { SOME_MUTATION } from './mutation-types'
...
store.commit(SOME_MUTATION)
7.Mutation 必須是同步函式
官方是這樣解釋的:
一條重要的原則就是要記住 mutation 必須是同步函式。為什麼?請參考下面的例子:
mutations: {
someMutation (state) {
api.callAsyncMethod(() => {
state.count++
})
}
}
現在想象,我們正在 debug 一個 app 並且觀察 devtool 中的 mutation 日誌。每一條 mutation 被記錄,devtools 都需要捕捉到前一狀態和後一狀態的快照。然而,在上面的例子中 mutation 中的非同步函式中的回撥讓這不可能完成:因為當 mutation 觸發的時候,回撥函式還沒有被呼叫,devtools 不知道什麼時候回撥函式實際上被呼叫——實質上任何在回撥函式中進行的狀態的改變都是不可追蹤的。
所以我們為了能夠實現非同步操作,我們需要藉助Actions來實現,在Actions通過非同步提交 mutation從而實現非同步操作,Action 可以包含任意非同步操作,Action 提交的是 mutation,而不是直接變更狀態。