Vuex 的 Mutation 学习
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。
目录:
例子
新建一个 store.js 文件用于创建 store 实例:
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
// 回调函数会接受 state 作为其第一个参数
increment (state) {
state.count++
}
}
})
export default store
在组件 App.vue 中提交 mutation:
// App.vue
<template>
<!-- ... -->
</template>
<script>
import store from "./store.js";
export default {
data() {
return {}
},
created:function(){
setInterval(() => {
// 要唤醒一个 mutation handler,需要以相应的 type 调用 store.commit 方法
store.commit('increment');
console.log(store.state.count); // 1 2 3 4 ...
}, 1000);
}
}
</script>
将 store 注入到每个子组件
Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中(需调用 Vue.use(Vuex)):
// main.js
import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'
import store from './store.js'
Vue.use(Vuex); // 调用Vue.use(Vuex)
new Vue({
el: '#app',
store, // “注入”
render: h => h(App)
})
再在 App.vue 中提交 mutation:
// App.vue
<template>
<!-- ... -->
</template>
<script>
// import store from "./store.js"; // 现在可以不用在每个 vue 组件中导入 store 实例了
export default {
data() {
return {}
},
created:function(){
setInterval(() => {
this.$store.commit('increment');
console.log(this.$store.state.count); // 1 2 3 4 ...
}, 1000);
}
}
</script>
提交载荷(Payload)
可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload):
// store.js
mutations: {
increment (state, payload) {
state.count += payload.amount;
}
}
// App.vue
created:function(){
//载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读
store.commit('increment', {
amount: 10
});
console.log(store.state.count); // 10
}
对象风格的提交方式
提交 mutation 的另一种方式是直接使用包含 type 属性的对象:
// App.vue
store.commit({
type: 'increment',
amount: 10
})
// store.js
mutations: {
// 当使用对象风格的提交方式,整个对象都作为载荷传给 mutation 函数
increment (state, payload) {
state.count += payload.amount
}
}
mapMutations 辅助函数
可以在组件中使用 this.$store.commit(‘xxx’) 提交 mutation,或者使用 mapMutations 辅助函数将组件中的 methods 映射为 store.commit 调用(需要在根节点注入 store)。
// store.js
mutations: {
increment (state) {
state.count++
}
}
// App.vue
import { mapMutations } from 'vuex'
export default {
created:function(){
this.increment();
console.log(this.$store.state.count); // 1
},
methods: {
...mapMutations([
'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
// ...
]}
}
}
mapMutations 也支持载荷:
// store.js
mutations: {
increment (state, payload) {
state.count += payload.amount;
}
}
// App/.vue
import { mapMutations } from 'vuex'
export default {
created:function(){
this.increment({
amount: 10
});
console.log(this.$store.state.count); // 10
},
methods: {
...mapMutations([
'increment', // 将 `this.increment(amount)` 映射为 `this.$store.commit('increment', amount)`
// ...
]}
}
}
通过传入一个对象也可以起到起别名的作用:
// App/.vue
import { mapMutations } from 'vuex'
export default {
created:function(){
this.add({
amount: 10
});
console.log(this.$store.state.count); // 10
},
methods: {
...mapMutations({
add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
})
}
}
Mutation 需遵守 Vue 的响应规则
既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:
- 最好提前在你的 store 中初始化好所有所需属性。
- 当需要在对象上添加新属性时,你应该:
- 使用 Vue.set(obj, ‘newProp’, 123), 或者
- 以新对象替换老对象。例如,利用 stage-3 的对象展开运算符我们可以这样写:state.obj = { …state.obj, newProp: 123 }
注意
一条重要的原则就是要记住 mutation 必须是同步函数。