vuex (4)
Mutation
更改vuex的store中的状态的唯一方法时提交mutation. Vuex中的mutation非常类似于事件:每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler)、这个回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数:
const store = createStore({ state: { count : 1 }, mutations: { increment(state){ // 变更状态 state.count++; } } })
你不能直接调用一个mutation处理函数,这个选项更像是事件注册:“当触发一个类型为 increment” 的mutation时,调用此函数。
要唤醒一个mutation处理函数,你需要以相应的type调用 store.commit 方法:
store.commit方法
提交载荷 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 属性的对象:
// ...
mutations: {
increment (state, payload){
state.count += payload.amount;
}
}
store.commit({ type:'increment', amount:10 })
Mutation 必须是同步函数
一条重要原则就是要记住 mutation 必须是同步函数,为什么呢?
mutations: { someMutation (state){ api.callAsyncMethod(() => { state.count++; }) } }
现在想象,我们正在 debug 一个 app 并且观察 devtool 中的 mutation 日志。每一条 mutation 被记录,devtools都需要捕捉到前一状态和后一状态的快照,然而,在上面的例子中 mutation 中的异步函数中的回调让这不可能完成:因为当 mutation 触发的时候,回调函数还没有被调用, devtools 不知道什么时候回调函数实际上被调用------实质上任何在回调函数中进行的状态改变都是不可追踪的。
在组件中使用 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')` }) } }
当你调用了两个包含异步回调的mutation来改变状态,你怎么知道什么时候回调和哪个先回调呢? 因此,在Vuex中, mutation都是同步事务