>[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" 导致的状态变更都应该在此刻完成。
~~~