為什么vuex的Mutations是同步,而Actions是異步

vuex[1]的mutations與actions有什么區(qū)別,除了用法上mutation是同步,actions是異步,這里的同步與異步指的是commitordispatch?并不是,同步指mutations方的內(nèi)部是同步的,而actions內(nèi)部可以是異步的,并且修改數(shù)據(jù)只能在mutations中修改,在actions中異步操作的副作用結(jié)果是通過(guò)mutations來(lái)記錄。本文是一篇筆者記錄vuex關(guān)于mutations與actions的筆記。

正文開(kāi)始...

避坑
如果使用vue-cli2模版搭建的基礎(chǔ)項(xiàng)目,注意,如果使用vue版本是2,當(dāng)你默認(rèn)安裝vuex肯定是4.x版本了,這里需要注意的是,你要降低vuex版本到3.x版本,不然store掛載不到vue上,訪問(wèn)的this.$store就是undefined

mutation
當(dāng)我們修改數(shù)據(jù),只能通過(guò)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)
    }
  }
})
在頁(yè)面中

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)
      })
    }
  }
}
我們修改數(shù)據(jù)就是$store.commit('eventName', payload),當(dāng)我們觸發(fā)commit時(shí),實(shí)際上是已經(jīng)在異步請(qǐng)求回調(diào)里獲取了數(shù)據(jù)。

但是官方在描述mutation有這么說(shuō),mutation內(nèi)部必須是同步函數(shù),異步會(huì)導(dǎo)致內(nèi)部狀態(tài)難以追蹤,devtool難以追蹤state的狀態(tài)

...
mutations: {
    storeData (state, payload) {
      mockFeatchData().then((res) => {
        console.log(res)
         state.data = state.data.concat(res)
      })
    }
},
也就是說(shuō)上面這段代碼,當(dāng)我們?cè)趍utations中的storeData中使用了異步函數(shù),我們?cè)?store.commit('storeData')時(shí),很難追蹤state的狀態(tài),因?yàn)樵赾ommit觸發(fā)mutations事件時(shí),異步的回調(diào)函數(shù)不知道什么時(shí)候執(zhí)行,所以難以追蹤。

mutations是同步事務(wù),假設(shè)在mutations有多個(gè)異步的調(diào)用,你很難確定這些異步哪些先執(zhí)行,很難追蹤state的變化,所以也給調(diào)試帶來(lái)了一定難度

話說(shuō)回來(lái),這么寫也確實(shí)是可以做到更新state的值,如果我不用vuetool這個(gè)工具,貌似也沒(méi)毛病

既然mutations是同步的事情,那么異步官方就使用了actions方案

actions
actions里面可以做異步操作,但是并不是直接修改數(shù)據(jù),提交的是mutations里面的方法

mutations: {
    storeData (state, payload) {
      state.data = state.data.concat(payload)
    }
},
actions: {
    setStoreData ({ commit }) {
      mockFeatchData().then((res) => {
        commit('storeData', res)
      })
    }
 }
在頁(yè)面中就是這樣觸發(fā)actions的






 methods: {
    handleData () {
      this.$store.dispatch('setStoreData')
    }
  }
我們把異步操作放在了actions的方法里面,你會(huì)發(fā)現(xiàn)mockFeatchData這是一個(gè)異步操作后的結(jié)果,然后通過(guò)commit傳給了mutations中

在actions執(zhí)行異步操作,將結(jié)果給了mutations,mutations中同步修改狀態(tài)state,使得actions的操作在mutations中有記錄。

在actions中也可以有多個(gè)異步操作

 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)
      })
    }
  }
頁(yè)面上是這樣觸發(fā)actions的

 handleText () {
      this.$store.dispatch('setStoreText', `hello,${Math.random()}`)
    }
這里我們也可以用對(duì)象的方式

 handleText () {
    this.$store.dispatch({
    type: 'setStoreText',
    payload: `hello,${Math.random()}`
})
不過(guò)此時(shí)注意actions中獲取值需要解構(gòu)才行

setStoreText ({ dispatch, commit }, {payload}) {
      dispatch('setStoreData').then(() => {
        console.log(222, payload)
        commit('storeText', payload)
      })
}
在actions可以dispatch另一個(gè)異步的操作,也就是等一個(gè)任務(wù)完成了后,可以執(zhí)行另一個(gè)commit

看到這里貌似這里有點(diǎn)想到,為啥所有的異步操作放在actions里面了,mutation只負(fù)責(zé)修改state,所有異步操作產(chǎn)生的副作用的結(jié)果都統(tǒng)統(tǒng)交給了mutation,這樣很好保證devtool了對(duì)數(shù)據(jù)的追蹤。

總結(jié)
靈魂拷問(wèn),為什么會(huì)有actions中是異步,而mutations是同步,從官方解釋來(lái)看,修改state數(shù)據(jù)必須只能mutations中修改,而假設(shè)mutions內(nèi)部有異步,那么會(huì)帶來(lái)devtool無(wú)法準(zhǔn)確追蹤state變化,因?yàn)槎鄠€(gè)異步并不知道哪個(gè)異步會(huì)先執(zhí)行完。但是話說(shuō)回來(lái),mutations中有異步,依然可以修改state啊,因?yàn)闃I(yè)務(wù)中我并不太需要知道devtool是如何追蹤state的變化,但是為了遵從規(guī)范,所有的異步都在actions中處理,mutations只集中干一件事,直接修改state值

actions是異步操作的,actions中可以有多個(gè)異步操作,但是最終的結(jié)果依然是交給mutations去修改的,也就是說(shuō)actions中異步操作的副作用統(tǒng)一交給了mutations去記錄

多個(gè)異步任務(wù)可以在actions中觸發(fā),dispatch('xxx')返回的是一個(gè)Promise

本文code example[2]

參考資料
[1]
vuex: https://v3.vuex.vuejs.org/zh/guide/mutations.html

[2]
code example: https://github.com/maicFir/lessonNote/tree/master/vue/06-vuex-test

作者:Maic


歡迎關(guān)注微信公眾號(hào) :web技術(shù)學(xué)苑