>[success] 更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation
**所有state中數據的修改必須通過提交 mutation的方式**
mutation 都有一個字符串的**事件類型 (type)**和 一個**回調函數 (handler)**。這個回調函數就是我們實際進行狀態更改的地方,并且它會接受 state 作為第一個參數:
~~~
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 變更狀態
state.count++
}
}
})
~~~
調用**store.commit**方法提交mutation 進行修改
> 這種提交修改的方式類似于事件系統,在mutations中注冊事件處理函數,然后使用store.commit()觸發事件
~~~
store.commit('increment')
~~~
> `store.commit()`用來觸發`mutations`
> `store.dispatch()`用來觸發`Action`
## 二:提交負載(參數)
你可以向`store.commit`傳入額外的參數,即 mutation 的**載荷(payload)**:
~~~
// ...
mutations: {
increment (state, n) {
state.count += n
}
}
~~~
~~~
store.commit('increment', 10)
~~~
在大多數情況下,載荷應該是一個對象,這樣可以包含多個字段并且記錄的 mutation 會更易讀:
~~~
// ...
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
~~~
~~~
store.commit('increment', {
amount: 10
})
~~~
## **對象風格的提交方式**
提交 mutation 的另一種方式是直接使用包含`type`屬性的對象:
~~~
store.commit({
type: 'increment',
amount: 10
})
~~~
當使用對象風格的提交方式,整個對象都作為載荷傳給 mutation 函數,因此 handler 保持不變:
~~~
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
~~~
## **使用常量替代 Mutation 事件類型**
使用常量替代 mutation 事件類型在各種 Flux 實現中是很常見的模式。這樣可以使 linter 之類的工具發揮作用,同時把這些常量放在單獨的文件中可以讓你的代碼合作者對整個 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 風格的計算屬性命名功能來使用一個常量作為函數名
// 等價es5中的mutations[SOME_MUTATION] = function(){}
[SOME_MUTATION] (state) {
// mutate state
}
}
})
~~~
用不用常量取決于你——在需要多人協作的大型項目中,這會很有幫助。但如果你不喜歡,你完全可以不這樣做。
## **Mutation 必須是同步函數**
**Mutation必須是同步,因為異步無法跟蹤狀態的變化,無法知道回調函數什么時候觸發,狀態什么時候改變,這將會帶來調試上的噩夢。
**
### 在組件中提交 Mutation
你可以在組件中使用`this.$store.commit('xxx')`提交 mutation,或者使用`mapMutations`輔助函數將組件中的 methods 映射為`store.commit`調用(需要在根節點注入`store`)。
~~~
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`
// `mapMutations` 也支持載荷:
'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.commit('incrementBy', amount)`
]),
...mapMutations({
add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
})
}
}
~~~
## **下一步:Action**
在 mutation 中混合異步調用會導致你的程序很難調試。例如,當你調用了兩個包含異步回調的 mutation 來改變狀態,你怎么知道什么時候回調和哪個先回調呢?這就是為什么我們要區分這兩個概念。在 Vuex 中,**mutation 都是同步事務**:
~~~
store.commit('increment')
// 任何由 "increment" 導致的狀態變更都應該在此刻完成。
~~~