vuex 基础使用的各种姿势(2)Mutations、Actions
本篇文章仅适合基础回顾,不具备深度
之前已经写了 vuex 的基本定义和使用,以及 Store、State、Getter 的相关内容,文章地址:
一、Mutation
之前文章已经说明了获取 state 的方式有两种,分别是 this.$store.state.num
这种直接获取的方式,以及通过 getter 定义的方式获取 this.$store.getter.num
。
而修改 state 不能直接修改对象或者覆盖对象的属性,因为我们遵循的是单一状态树的管理原则,不允许通过 this.$store.state.num = 3
修改 state。
定义一个 mutation:(已经存在 state.count
)
const mutations = {
increment(state){
state.count ++ ;
},
}
定义的 mutations 对象将挂载到 Store 的 mutations 属性上。
mutations 的每个属性都是以方法的形式定义,默认接收一个参数,而这个参数实际上就是 Store 的 state 对象,只有在 mutations 的属性中直接通过 state.xxx = xxx
修改 state。
而 mutations 的方法this.$store.mutations.xxx(xx)
去调用的,而是通过主动触发的。
可以打印 this.$store
查看 Store 的属性,可以发现, mutations 是以 _mutations
的私有属性形式存在的,因此并不能直接调用(不能是指不允许)。
从上面的属性列表中可以发现 commit
属性,而这个属性是一个 function,用来触发 mutations 中定义的 mutation,比如上面定义了 increment
,可以通过以下方式触发 mutation:
this.$store.commit('increment');
效果:
1、playload 传参
上面定义的 increment
mutation 实际上是没有传递参数的, state 是默认的参数,mutation 传参在 vuex 中称为 payload。
下面的 incrementPlayload
mutation 传递了额外的参数 num2,作用是每次触发 incrementPlayload
的时候,state.count 不是自增 1 而是加上 num2 :
incrementPlayload(state, num2) {
return state.count = state.count + num2;
}
playload 的触发形式与之前的不同之处在于多传递一个参数而已:
this.$store.commit('incrementPlayload', 2);
上面触发 incrementPlayload
之后效果如下:
(state, num1, num2)
是无效的
因此一般建议是通过对象的方式定义 playload,然后通过对象的方式传递 playload,这样子既能够多传递一些数据,也便于组件开发者的理解,比如
incrementPlayloadObj(state, playload) {
return state.count = state.count + playload.num;
}
而在触发的时候,如下传递参数即可:
this.$store.commit('incrementPlayloadObj', {num: 2});
而针对上面这种情况,也可以给 commit 直接传递一个对象,只需要一个对象参数即可:
this.$store.commit({ type: 'incrementPlayloadObj', num: 2});
type 是固定参数,用来指定触发哪个 mutation,这种形式比较尴尬的就是 type 属性已经是预置被用掉了。
2、一些约定或者是规范
- mutation 中如果是修改对象则必须遵循 vue 的响应原则, 也就是全覆盖。
这里的对象包括了 array,如果修改 object array 一般都是通过 Object.assign({},obj1,obj2) 的形式或者 array 的重新赋值整个新的 array,不能直接修改属性。
- mutation 中必须是同步操作
mutation 中如果是异步方法,会导致在触发 mutation 的时候回调还没有触发,因此不知道什么时候去改变状态,对于状态的改变是无法追踪的。
- mutation 的名称一般建议使用常量代替字符串
这也是 FLUX 架构推荐的方式,不过多阐述其好处,坏处就是各种引入引出。
3、mapMutation
mapMutations 类似于 mapState
mapGetters
也是一种辅助方法,能够在某些程度上简化代码。
以下代码来文档,在 组件 中直接映射到 methods 中,可以重命名等。
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)`
])
}
}
二、Action
上面提到 mutations 中不能存在 异步操作,因为无法准备的进行状态变更的追踪,会造成意想不到的效果。
而 Action 则是在 mutation 之前(可以这么理解)进行的操作,Action 最终是对 mutation 进行 commit,因此 Action 并不直接修改 state,因此 Action 中可以存在任何的异步操作。
actions 的定义类似于 其他几个属性,只不过默认的参数不一样,默认带过来的是与 Store 有相同属性和方法的对象,并不直接就是 Store(
打印 context 对象可以发现:
const actions = {
incrementAction(context) {
console.log(context);
context.commit('increment');
}
}
上面的 action 中实际上是最终触发了 increment
这个 mutation。
触发 Action,Store 的属性和方法中, commit()
是用来触发 mutation 的,而 dispatch()
则是用来触发 action 的:
this.$store.dispatch('incrementAction');
1、Action playload
action 的 playload 与 mutation 一模一样,比如一个参数从 action 再传递到 mutation (因为 mutation 是最终修改 state 的地方):
incrementActionPlayload(context, playload) {
console.log(context);
store.commit('incrementPlayloadObj', {
num: playload.num2
});
}
而在触发的时候,传递参数的方式也是一样:
this.$store.dispatch('incrementActionPlayload', {num : 2});
效果:
2、异步 action
如果存在异步操作比如数据请求,则需要放在 action 中:
incrementAction(context) {
setTimeout(() => {
context.commit('increment');
}, 500);
},
触发的方式不发生任何变化,效果如下:
3、mapActions
mapActions 也是为了方便在组建中去重新定义和使用 Actions,与 mapState mapGetters mapMutations 一样的用法就不重复了。
4、Actions 的组合
作为的组合就是两个 actions 可能相互依赖,比如 actionB 依赖于 actionA 之后,则可以通过 Promise 的方式去实现:
- actionA commit 之后返回一个 Promise.resolve
- actionB 中,先 dispatch('actionA') 然后在
dispatch('actionA').then()
中去 commit mutation。
这样的好处是,如果要 dispatch(actionB),则会首先 dispatch(actionA),而单独 dispatch(actionA) 又不会对 actionA 造成什么影响。
文章版权:Postbird-There I am , in the world more exciting!
本文链接:http://ptbird.cn/vuex-base-use-2.html
转载请注明文章原始出处 !