小编今天继续和大家一起学习和探讨Vuex。让我们继续探索Vuex的其他特性。3.Mutation在上一篇文章中我们已经知道了对于Vuex数据中的数据不能像数据中的数据那样直接修改,那么在修改State中的数据时应该怎么做呢?Vuex提供了统一修改的Mutation方法,以状态作为第一个参数,就像这样,conststore=newVuex.Store({state:{count:1},mutations:{increment(state){//changestatestate.count++}}})来触发这个函数,只需要store.commit('increment')同样的,我们在提交的时候也可以多传一个参数,就是官方说的提交负载(Payload)website,likethis//...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})同样,官方提出了“对象提交样式”,以类型作为提交对象的key来触发相应的Mutation中的sponding方法,像这样store.commit({type:'increment',amount:10})mutations:{increment(state,payload){state.count+=payload.amount}}小编稍微说一下更多在这里。对于对象,js在新语法中做了很多扩展,扩展运算符就是其中之一,它可以组合属性的相同值。同样,Linux的一些配置文件中也应该使用类似的思路。state.obj={...state.obj,newProp:123}在实际项目中,我们很容易写错字符串。在上一篇文章中,小编提供了两种解决方案,一种是使用es6中的Symbol可以实现,一种可以通过定义常量来实现,这在Vuex中也有对应的影子。//mutation-types.jsexportconstSOME_MUTATION='SOME_MUTATION'//store.jsimportVuexfrom'vuex'import{SOME_MUTATION}from'./mutation-types'conststore=newVuex.Store({state:{...},mutations:{//我们可以使用ES2015风格的计算属性命名特性,使用一个常量作为函数名在component中,和前面的mapGetters类似,提供了mapMutations方法。import{mapMutations}from'vuex'exportdefault{//...方法:{...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必须是一个同步函数。为什么?请参考以下示例:mutations:{someMutation(state){api.callAsyncMethod(()=>{state.count++})}}现在假设我们正在调试一个应用程序并在devtool中观察mutation日志。每个突变都会被记录下来,devtools需要捕捉前一个状态和下一个状态的快照。然而,上面示例中变异中异步函数中的回调使得这成为不可能:因为当变异触发时回调函数尚未被调用,devtools不知道回调函数何时被实际调用——本质上任何状态变化在回调函数是不可追踪的。至于异步函数,怎么处理,就是Vuex4中的Actions。ActionsAction类似于mutation,不同的是Action提交mutation,而不是直接改变state;Action可以包含任何异步操作。让我们看一个简单的actionconststore=newVuex.Store({state:{count:0},mutations:{increment(state){state.count++}},actions:{increment(context){context.commit('increment')}}})我们在分发action的时候,只需要这样,store.dispatch('increment')并且在action里面,允许异步操作,这也是和mutation不同的,像这样actions:{incrementAsync({commit}){setTimeout(()=>{commit('increment')},1000)}}同样的action也支持同样的加载方式和对象方式进行分发//withloadForm分发store.dispatch('incrementAsync',{amount:10})//以对象的形式分发store.dispatch({type:'incrementAsync',amount:10}),也支持简写import{mapActions}from'vuex'exportdefault{//...方法:{...mapActions(['increment',//将`this.increment()`映射到`this.$store.dispatch('increment')`//`mapActions`也支持负载:'incrementBy'//映射`this.incrementBy(amount)`到`this.$store.dispatch('incrementBy',amount)`]),...mapActions({add:'increment'//将`this.add()`映射到`this.$store.dispatch('increment')`})}}同样的,我们在使用action的时候,也可以组合使用,结合Promise的特点,还有async和await写的更好,更容易维护,并且观看这样的代码会更舒服:{actionA({commit}){returnnewPromise((resolve,reject)=>{setTimeout(()=>{commit('someMutation')resolve()},1000)})}}store.dispatch('actionA').then(()=>{//...})actions:{//...actionB({dispatch,commit}){returndispatch('actionA').then(()=>{commit('someOtherMutation')})}}最后,如果我们使用async/await(打开新窗口),我们可以组合操作如下://假设getData()和getOtherData()返回Promiseactions:{asyncactionA({commit}){commit('gotData',awaitgetData())},asyncactionB({dispatch,commit}){awaitdispatch('actionA')//等待actionA完成commit('gotOtherData',awaitgetOtherData())}}参考:https://vuex.vuejs.org/zh/也可以扫一扫二维码,关注我微信公众号,蜗牛全栈
