ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
### Mutation 更改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是,调用此函数。” 触发方法 ``` store.commit('increment') ``` #### 提交荷载(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 }) ``` #### 对象风格的提交方式 另一种方式是直接使用包含type属性的对象: ``` store.commit({ type: 'increment', amount: 10 }) ``` 当使用对象风格的提交方式,整个对象都作为载荷传给mutation函数,因此handler保持不变 ``` mutations: { increment ( state, payload){ state.ount+=payload.amount } } ``` #### Mutation 需遵守Vue的响应规则 Vuex的store中的状态是响应式的,当我们变更状态是,**监视状态的Vue组件也会自动更新**。 注意事项: 1. 最好提前在你的store中**初始化好所有所需属性**。 2. 当需要在对象上添加新属性时 * Vue.set(obj, 'newProp', 123) * 已新对象替换老对象。state.obj={...state.obj,newProper:123} * state.obj=JSON.parse(JSON.stringify(state.obj)) #### 使用常量替代Mutation事件类型 很常见的模式。四linter之类的工具发挥作用,同时把这些常量放在单独的文件中可以让代码的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:{ //我们可以使用ES2-15风格的计算属性命名功能更来使用一个常量作为函数名 [SOME_MUTATION] ( state ){ // mutate state } } }) ``` 在需要多人协作的大型项目中,这会很有帮助。 #### Mutation必须是同步函数 重要原则:**mutation必须是同步函数**。 ``` mutations: { someMutation ( state ) => { api.callAsynMethod( () => { state.count++ }) } } ``` 当mutation触发的时候,回调函数还没有被调用,devtools不知道什么时候回调函数实际上被调用--实质上**任何在回到函数中进行的状态的改变都是不可追踪的**。 #### 在组件中提交Mutation 在组件中使用 `this.$store.commit( 'xxx' )` 提交mutation,或者使用mapMutation辅助函数将组件中的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都是同步事务: ``` store.commit('increment') // 任何由 "increment" 导致的状态变更都应该在此刻完成。 ``` #### 小实例 1. types.js ``` export const INCREMENT_COUNT = 'INCREMENT_COUNT'; export const DECREMENT_COUNT = 'DECREMENT_COUNT'; export const MULTIPLE_NUM = 'MULTIPLE_NUM'; ``` 2. mutations.js ``` import * as types from './types'; export const testMutation = { [types.INCREMENT_COUNT](state){ return state.count++; }, [types.DECREMENT_COUNT](state){ return state.count--; }, [types.MULTIPLE_NUM](state, payload){ return state.count*=payload.num; }, } ``` 3.hello.js ``` import {testMutation} from '../mutations'; const state = { count:1 } export default { state, mutations: testMutation } ``` 4. store.js ``` import Vue from 'vue'; import Vuex from 'vuex'; import helloWorld from './modules/hello_world'; Vue.use(Vuex); export default new Vuex.Store({ modules:{ hello:helloWorld, } }) ``` 5. main.js ``` import store from './vuex/store'; new Vue({ el: '#app', store, router, components: { App }, template: '<App/>' }) ``` 6. HelloWorld.vue ``` <button @click="increment">+++</button>{{count}} <button @click="decrement">----</button> <button @click="multiple()">*</button> computed:{ ...mapState({ count: state => state.hello.count, }), }, methods:{ ...mapMutations({ increment:'INCREMENT_COUNT',//this.$store.commit('INCREMENT_COUNT') decrement:'DECREMENT_COUNT',//this.$store.commit('DECREMENT_COUNT') }), multiple(){ this.$store.commit({type:'MULTIPLE_NUM',num:10}) } } ```