每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 变更状态 state.count++ } } })
以相应的 type 调用 store.commit 方法:
store.commit('increment')
提交载荷(Payload)
向 store.commit
传入额外的参数 :载荷(payload)
// ... mutations: { increment (state, n) { state.count += n } }
调用:
store.commit('increment', 10)
载荷是一个对象时:
// ... mutations: { increment (state, payload) { state.count += payload.amount } }
调用:
store.commit('increment', { amount: 10 })
对象风格:
mutations: { increment (state, payload) { state.count += payload.amount } }
调用:
store.commit({ type: 'increment', amount: 10 })
其他规则:
最好提前在你的 store 中初始化好所有所需属性。
当需要在对象上添加新属性时,你应该
使用
Vue.set(obj, 'newProp', 123)
, 或者以新对象替换老对象。例如,利用对象展开运算符我们可以这样写:
state.obj = { ...state.obj, newProp: 123 }
使用常量替代 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 必须是同步函数
index.js
import Vue from 'vue'; import 'es6-promise/auto' import Vuex from 'vuex'; Vue.use(Vuex); const store = new Vuex.Store({ state: { count: 0, countPlus: 1, countLength: 1, productName: '', productPrice: 0, productTotal: 0, }, getters: { countCache: function (state) { return state.count + state.countPlus; }, countFunc: function (state) { return function (num) { return state.countPlus > num; } } }, mutations: { increment(state) { state.count++; state.countPlus = state.count + 1; state.countLength = state.count.toString().length; }, decrement(state) { state.count--; state.countPlus = state.count + 1; state.countLength = state.count.toString().length; }, calculate(state, payload) { state.productPrice = payload.price; state.productName = payload.name; state.productTotal = state.productPrice * state.count; }, }, }); export default store;
StoreComponent.vue:
<template> <div> <button @click="increment"> {{count}}</button> <button @click="decrement"> {{count}}</button> <span> Plus one: {{ countPlus }}</span> <span> Length: {{ countLength}}</span> <span> Plus one Length: {{ countPlusLength}}</span> <span> countAndCountPlusCache: {{ countPCountPlusCache}}</span> <span> countAndCountPlusFunc: {{ countPCountPlusFunc}}</span> <div> <span> countCache: {{ countCa}}</span> <span> countFunc: {{ countFu(12)}}</span> </div> <div> <table> <tr> <th>Product Name</th> <th>Product Count</th> <th>Product Price</th> <th>Product Total</th> </tr> <tr> <th>{{pName}}</th> <th>{{count}}</th> <th>{{pPrice}}</th> <th>{{pTotal}}</th> </tr> </table> </div> <div> <input type="text" v-model="productName"> <input type="text" v-model="productPrice"> <button @click="calculate">Calculate</button> </div> </div> </template> <script> import {mapState} from 'vuex'; import {mapGetters} from 'vuex'; export default { name: "StoreComponent", data: function () { return { productName: '', productPrice: 0, } }, // computed: { // count() { // return this.$store.state.count; // }, // // }, computed: { countPlusLength() { return this.countPlus.toString().length; }, countPCountPlusCache() { return this.$store.getters.countCache; }, countPCountPlusFunc() { return this.$store.getters.countFunc(2); }, ...mapState({ count: state => state.count, countPlus: 'countPlus', countLength(state) { return state.countLength; }, pName: 'productName', pPrice: 'productPrice', pTotal: 'productTotal', }), // 使用对象展开运算符将 getter 混入 computed 对象中 // ...mapGetters([ // 'countCache', // 'countFunc', // ]), ...mapGetters({ // 把 `this.countCa` 映射为 `this.$store.getters.countCache` countCa: 'countCache', // 把 `this.countFu` 映射为 `this.$store.getters.countFunc` countFu: 'countFunc', }), }, // computed: mapState([ // 'count', // 'countPlus', // 'countLength', // ]), methods: { increment() { this.$store.commit('increment'); }, decrement() { this.$store.commit('decrement'); }, calculate() { let payload = { price: this.productPrice, name: this.productName, }; // this.$store.commit('calculate', payload); // this.$store.commit({ // type: 'calculate', // price: this.productPrice, // name: this.productName, // }); }, } } </script> <style scoped> </style>
效果:
mapMutations
辅助函数
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')` }) } }
StoreComponent.vue:
<template> <div> <button @click="increment"> {{count}}</button> <button @click="decrement"> {{count}}</button> <span> Plus one: {{ countPlus }}</span> <span> Length: {{ countLength}}</span> <span> Plus one Length: {{ countPlusLength}}</span> <span> countAndCountPlusCache: {{ countPCountPlusCache}}</span> <span> countAndCountPlusFunc: {{ countPCountPlusFunc}}</span> <div> <span> countCache: {{ countCa}}</span> <span> countFunc: {{ countFu(12)}}</span> </div> <div> <table> <tr> <th>Product Name</th> <th>Product Count</th> <th>Product Price</th> <th>Product Total</th> </tr> <tr> <th>{{pName}}</th> <th>{{count}}</th> <th>{{pPrice}}</th> <th>{{pTotal}}</th> </tr> </table> </div> <div> <input type="text" v-model="productName"> <input type="text" v-model="productPrice"> <button @click="calculate({ type: 'calculate', price: productPrice, name: productName,})">Calculate </button> </div> </div> </template> <script> import {mapState} from 'vuex'; import {mapGetters} from 'vuex'; import {mapMutations} from 'vuex'; export default { name: "StoreComponent", data: function () { return { productName: '', productPrice: 0, } }, // computed: { // count() { // return this.$store.state.count; // }, // // }, computed: { countPlusLength() { return this.countPlus.toString().length; }, countPCountPlusCache() { return this.$store.getters.countCache; }, countPCountPlusFunc() { return this.$store.getters.countFunc(2); }, ...mapState({ count: state => state.count, countPlus: 'countPlus', countLength(state) { return state.countLength; }, pName: 'productName', pPrice: 'productPrice', pTotal: 'productTotal', }), // 使用对象展开运算符将 getter 混入 computed 对象中 // ...mapGetters([ // 'countCache', // 'countFunc', // ]), ...mapGetters({ // 把 `this.countCa` 映射为 `this.$store.getters.countCache` countCa: 'countCache', // 把 `this.countFu` 映射为 `this.$store.getters.countFunc` countFu: 'countFunc', }), }, // computed: mapState([ // 'count', // 'countPlus', // 'countLength', // ]), methods: { increment() { this.$store.commit('increment'); }, decrement() { this.$store.commit('decrement'); }, // calculate() { // let payload = { // price: this.productPrice, // name: this.productName, // }; // // this.$store.commit('calculate', payload); // // // this.$store.commit({ // // type: 'calculate', // // price: this.productPrice, // // name: this.productName, // // }); // }, ...mapMutations([ 'calculate', ]), } } </script> <style scoped> </style>
效果: