Vuex 核心概念之 Mutation && mapMutations

67 阅读1分钟

Vuex 核心概念之 Mutation && mapMutations

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

const state = {
  count: 1
}
const mutation = {
  increment (state) {
    // 变更状态
    state.count++
  }
}

// 创建store并暴露store
export const store = new Vuex.Store({
  state,
  mutations
})

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

store.commit('increment')

提交载荷(Payload)

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

mutations: {
  increment (state, n) {
    state.count += n
  }
}

在组件中使用只需:

this.$store.commit('increment', 10)

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

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}
this.$store.commit('increment', {
  amount: 10
})

对象风格的提交方式

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

this.$store.commit({
  type: 'increment',
  amount: 10
})

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

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }
}

使用常量替代 Mutation 事件类型

使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。同时可以把这些常量单独抽离到一个文件中,方便维护

// mutation-types.js
export const INCREMENT = 'increment'
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import { INCREMENT } from './mutation-types'
Vue.use(Vuex)

const state = {
  count: 1
}
const mutation = {
   [INCREMENT](state) {
    // 变更状态
    state.count++
  },
  // 或者
  INCREMENT(state, payload){
    state.count += payload.data
  }
}

// 创建store并暴露store
export const store = new Vuex.Store({
  state,
  mutations
})

用不用常量取决于你——在需要多人协作的大型项目中,这会很有帮助。但如果你不喜欢,你完全可以不这样做。

Mutation 必须是同步函数

由于每一条mutaion被记录的时候,devtools都需要捕捉到前一状态和后一状态的快照。假设此时是异步的,devtools将不知道什么时候异步函数会执行完,将无法对其进行追踪。

mapMutations

首先在组件中提交mutation可以使用this.$store.commit('xxx') 也可以使用mapMutations辅助函数将组件中的methods映射为store.commit调用

<div>{{$store.state.count}}</div>
<button @click="changeCount(6)">修改count的值</button>

import { mapMutations } from 'vuex'

export default {
  methods: {
    // 提交mutation的普通写法
    changeCount(n){
      this.$store.commit({
        type: 'INCREMENT',
        data: n
      })
    },
    // 借助 mapMutations 生成提交mutations的方法
    // 对象写法
    // 对象中的key相当于上面的方法名,value相当于type,值会自动传递
    ...mapMutations[{changeCount: 'INCREMENT'}]   
    
    // 数组写法
    ...mapMutations(['INCREMENT'])   // 只需要写mutations中的type即可
  }
}