更改Vuex的store中的状态唯一方法是提交mutation。
Vuex中的mutation非常类似于事件:每个mutation都有一个字符串的 事件类型(type)和一个回调函数(handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接收state作为第一个参数:

  1. const store = new Vuex.Store({
  2. state:{
  3. count:1
  4. },
  5. mutations:{
  6. increment(state){
  7. // 变更状态
  8. state.count++
  9. }
  10. }
  11. })

你不能直接调用一个 mutation handler。这个选项更像是事件注册:“当触发一个类型为 increment 的mutation时,调用此函数”。要唤醒一个mutation handler,你需要以相应的type调用store.commit 方式:

  1. store.commit('increment')

提交载荷(Payload)

你可用向 store.commit 传入额外的参数,即mutation 的 载荷 (payload):

  1. mutations:{
  2. increment(state,n){
  3. state.count += n
  4. }
  5. }
  6. store.commit('increment',10)

在大多数情况下,载荷应该时一个对象,这样可以包含多个字段并且记录的mutation会更易读:

  1. mutations:{
  2. increment(state,payload){
  3. state.count += payload.amount
  4. }
  5. }
  1. store.commit('increment',{amount:10})

对象风格的提交方式

提交 mutation 的另一种方式是直接使用包含 type 属性的对象

  1. store.commit({
  2. type:'increment',
  3. amount:10
  4. })

当使用对象风格的提交方式,整个对象都作为载荷传给mutation函数,因此handler保持不变:

  1. mutations:{
  2. increment(state,payload){
  3. state.count += payload.amount
  4. }
  5. }

Mutation 需遵守Vue的响应规则

既然 Vuex 的store 中的状态是响应式的,那么当我们变更状态时,监视状态的Vue组件也会自动更新。这也意味着 Vuex 中的mutation 也需要与使用 Vuex 一样遵守一些注意事项:

  1. 最好提前在你的store中初始化好所有所需属性。
  2. 当需要在对象上添加新属性时,你应该
    1. 使用Vue.set(obj,’newProp’,123) 或者
    2. 以新对象替换老对象。例如,利用对象展开运算符
      1. state.obj = {...state.obj,newProp:123}

      使用常量代替 Mutation 事件类型

      使用常量代替 mutation 事件类型在各种 Flux实现中是很常见的模式。这样可以使 linter之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对真个app包含的mutation 一目了然:
      1. // mutation-types.js
      2. export const SOME_MUTATION = 'SOME_MUTATION
      ```javascript // store.js

import Vuex from ‘vuex’ import { SOME_MUTATION }from ‘./mutaion-types’

const store = new Vuex.Store({ state:{}, mutations:{ // ES2015 风格的计算属性命名功能来使用一个常量作为函数名 SOME_MUTATION{ // mutate state } } })

  1. 用不用常量取决于你,——在需要多人协作的大型项目中,这会很有帮助,但如果你不喜欢,你完全可以不这样做
  2. <a name="9y5ss"></a>
  3. ## Mutation 必须是同步函数
  4. 一条重要的原则就是要记住 mutation **必须是同步函数。**why 请参考下面的例子:
  5. ```javascript
  6. mutations:{
  7. someMutaion(state){
  8. api.callAsyncMethod(()=<{
  9. state.count++
  10. })
  11. }
  12. }

现在想象。我们正在 debug 一个app 并且观察devtool 中的mutation 日志。每一条mutaion被记录,devtools都需要捕捉到前一状态和后一状态的快照。然而,在上面的例子中mutaion 中的异步函数中的回调让这不可能完成:因为当mutaion 触发的时候,回调函数还没有被调用, devtools 不知道什么时候回调函数实际上被调用——实质上任何回调函数中进行的状态的改变都是不可追踪的

在组件中提交Mutation

你可以在组件中使用 this.$store.commit(‘xxx’) 提交mutaion 或者 使用 mapMutations 辅助函数将组件中的methods 映射为 store.commit 调用 ( 需要在根节点注入 store )

  1. import {mapMutations} from 'vuex'
  2. export default{
  3. methods:{
  4. ...mapMutations([
  5. 'increment', //将this.increment() 映射为 this.$store.commit('increment')
  6. //使用 increment 或者 this.increment
  7. // mapMutations 也支持 载荷
  8. 'incrementBy'//将this.incrementBy(amount) 映射为 this.$store.commit('incrementBy',amount)
  9. //直接使用 increment({amount:10}) 即可。不能带有this.increment(amount)
  10. ]),
  11. ...mapMutations({
  12. add:'increment' // 将this.add() 映射为 this.$store.commit('increment')
  13. // add(amount)、add()
  14. })
  15. }
  16. }

下一步 Action

在mutation 中混合异步调用会导致你的程序很难调试。例如,当你调用了两个包含异步回调的 mutation 来改变状态,你怎么知道什么时候回调和那个先回调呢? 这就是为什么我们要区别这两个概念。
在Vuex 中,mutation 都是同步事务:

  1. store.commit('increment')
  2. // 任何由 increment 导致的状态变更都应该在此刻完成

为了处理异步操作,让我们来看一看 active