vuex Mutations同步Actions异步原理解析
Maic 人气:0正文
vuex的mutations
与actions
有什么区别,除了用法上mutation
是同步,actions
是异步,这里的同步与异步指的是commit
ordispatch
?并不是,同步指mutations
方的内部是同步的,而actions
内部可以是异步的,并且修改数据只能在mutations
中修改,在actions
中异步的操作副作用是通过mutations
来记录。本文是一篇笔者记录vuex
关于mutations
与actions
的笔记。
避坑
如果使用vue-cli2
模版搭建的基础项目,注意,如果使用vue
版本是2,当你你默认安装vuex
肯定是4.x
版本了,这里需要注意的是,你要降低vuex
版本到3.x
版本,不然store
挂载不到vue
上
mutation
当我们修改数据,只能通过mutation
修改state
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export const store = new Vuex.Store({ state: { data: [] }, mutations: { storeData (state, payload) { state.data = state.data.concat(payload) } } })
在页面中
import { mockFeatchData } from '@/mock' export default { name: 'HelloWorld', data () { return { msg: 'Welcome to Your Vue.js App' } }, computed: { ...mapState({ dataList: state => state.data }) }, methods: { handleData () { mockFeatchData().then(res => { this.$store.commit('storeData', res) }) } } }
我们修改数据就是$store.commit('eventName', payload)
,当我们触发commit
时,实际上是已经在异步请求回调里获取了数据。
但是官方在描述mutation
有这么说,mutation
内部必须是同步函数,异步会导致内部状态难以追踪,devtool
难以追踪state
的状态
... mutations: { storeData (state, payload) { mockFeatchData().then((res) => { console.log(res) state.data = state.data.concat(res) }) } },
也就是说上面这段代码,当我们在mutations
中的storeData
中使用了异步函数,我们在$store.commit('storeData')
时,很难追踪state
的状态,因为在触发commit事件时,异步的回调函数不知道什么时候执行,所以难以追踪。
mutations
是同步事务,假设在mutations
有多个异步的调用,你很难确定这些异步哪些先执行,很难追踪state
的变化,所以也给调试带来了一定难度
话说回来,这么写也确实是可以做到更新state的值,如果我不用vuetool
这个工具,貌似也没毛病
既然mutations
是同步的事情,那么异步官方就使用了actions
方案
actions
actions
里面可以做异步操作,但是并不是直接修改数据,提交的是mutations
里面的方法
mutations: { storeData (state, payload) { state.data = state.data.concat(payload) } }, actions: { setStoreData ({ commit }) { mockFeatchData().then((res) => { commit('storeData', res) }) } }
在页面中就是这样触发actions
的
methods: { handleData () { this.$store.dispatch('setStoreData') } }
我们把异步操作放在了actions
的方法里面,你会发现mockFeatchData
这是一个异步操作后的结果,然后通过commit
传给了mutations
中
在actions
执行异步操作,将结果给了mutations
,mutations
中同步修改状态state
,使得actions
的操作在mutations
中有记录。
在actions
中也可以有多个异步操作
mutations: { storeData (state, payload) { state.data = state.data.concat(payload) }, storeText (state, payload) { state.text = payload } }, actions: { setStoreData ({ commit }) { mockFeatchData().then((res) => { console.log(res, '111') commit('storeData', res) }) }, setStoreText ({ dispatch, commit }, payload) { dispatch('setStoreData').then(() => { console.log(222) commit('storeText', payload) }) } }
页面上是这样触发actions
的
handleText () { this.$store.dispatch('setStoreText', `hello,${Math.random()}`) }
这里我们也可以用对象的方式
handleText () { this.$store.dispatch({ type: 'setStoreText', payload: `hello,${Math.random()}` })
不过此时注意actions
中获取值需要解构才行
setStoreText ({ dispatch, commit }, {payload}) { dispatch('setStoreData').then(() => { console.log(222, payload) commit('storeText', payload) }) }
在actions可以dispatch
另一个异步的操作,也就是等一个任务完成了后,可以执行另一个commit
看到这里貌似这里有点明白,为啥所有的异步操作放在actions
里面了,mutation
只负责修改state
,所有异步操作产生的副作用的结果都统统交给了mutation
,这样很好保证devtool
了对数据的追踪。
总结
灵魂拷问,为什么会有actions
中是异步,而mutations
是同步,从官方解释来看,修改state数据必须只能mutations
中修改,而假设mutions
内部有异步,那么会带来devtool
无法准确追踪state
变化,因为多个异步并不知道哪个异步会先执行完。但是话说回来,mutations
中有异步,依然可以修改state啊,因为业务中我并不太需要知道devtool
是如何追踪state
的变化,但是为了遵从规范,所有的异步都在actions
中处理,mutations
只集中干一件事,直接修改state
值
actions
是异步操作的,actions
中可以有多个异步操作,但是最终的结果依然是交给mutations
去修改的,也就是说actions
中异步操作的副作用统一交给了mutations
去记录
多个异步任务可以在actions
中触发,dispatch('xxx')
返回的是一个Promise
加载全部内容