Mutation
转变,改变
Vuex旗下的Mutation  只有 mutation 能动 State
更改 Vuex 的 store 中的状态 唯一方法是提交 mutation
Vuex 中的 mutation 类似于事件
每个 mutation 都有个字符串 事件类型 type 和 一个回调函数 handler ,回调函数是实际状态更改的地方,state 作为第一个参数:
const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) { // 变更状态
      state.count++
    }
  }
})
不能直接调用 mutation handler 当触发类型为 increment 的 mutation 时调用此函数
要唤醒 mutation handler 相应的 type 调用 store.commit 方法  store.commit('increment')

不能直接 store.mutations.increment() 来调用,Vuex 规定必须用 store.commit 来触发对应 type 的方法:
store.commit('increment')

传参
向 store.commit 传入额外的参数:
mutations: {
  increment (state, n) {
    state.count += n
  }
}
store.commit('increment', 10) // 调用
mutation 这个额外的参数10,官方取名:载荷payload  提交载荷  西红柿不叫西红柿 叫 tomato 掏码头 :>
人们往往不是败给陌生,而是败给了内心的恐惧

载荷是对象更加易读
mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
关于提交的方式,有两种:
// 把载荷和type分开提交
store.commit('increment', {
  amount: 10
})

//整个对象都作为载荷传给 mutation 函数
store.commit({
  type: 'increment',
  amount: 10
})

#提交载荷(Payload)
向 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 遵守 Vue 响应规则
Vuex 的 store 中的状态响应式,变更状态时 监视状态 Vue 组件自动更新, Vuex 中 mutation 与 Vue一样遵守事项
提前在 store 中初始化所需属性 需要在对象上添加新属性时 用 Vue.set(obj, 'newProp', 123)或 以新对象替换老对象
用对象展开运算符 state.obj = { ...state.obj, newProp: 123 }

#用常量替代 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 风格的计算属性命名功能 用一个常量作为函数名
    [SOME_MUTATION] (state) {      // mutate state
    }
  }
})
用常量取决于 多人协作的大型项目有帮助

#Mutation 必须同步函数
mutation 必须是同步函数
mutations: {
  someMutation (state) {
    api.callAsyncMethod(() => {
      state.count++
    })
  }
}
debug app 且观察 devtool 的 mutation 日志
mutation 被记录
devtools 需要捕捉到前一状态和后一状态的快照
mutation 异步函数中的回调让这不可能完成
因为 mutation 触发时,回调函数还没有被调用devtools 不知道什么时候回调函数

#在组件中提交 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 导致的状态变更都应该在此刻完成
处理异步操作 Action