vuex 源碼:深刻 vuex 之 state

前言

接下來咱們則開始要研究的是 vuex 的 store 對象。html

store 對象中有一個屬性叫 state。state 包含了所有的應用層級狀態。應用中的各個組件若使用了 state,則會保持與同步最新的狀態。state 就比如是 vue 中的 data,但它是整個應用的 data。vue

舉個簡單的例子:應用中的子組件 a 和子組件 b 用到了 state.count,兩個組件是非父子關係。這時,子組件 a 修改了 state.count,子組件 b 中的 state.count 也會相應修改。react

那咱們就來看看,vuex 是如何在各個組件中作到監聽 state 的屬性的git

注:本次閱讀的是 vuex 的 2.0.0 版本,源碼請戳 這裏github

解讀

在開始閱讀源碼以前,我一直有一個疑惑。我在組件 a 修改了 state.count,組件 b 是怎麼監聽到 state.count 的改變的?難道是 store 裏對 state 作了相似 object.defineproperty() 的處理。vuex

帶着疑惑,開始啦.....app

從哪開始切入呢?就從 store 對象被實例化的代碼中開始吧。ide

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0
  }
});

new Vue({
  el: '#app',
  store,
  // ...
});
複製代碼

store 對象是經過 new Vuex.Store 被實例化出來的,打開 src/index.js 文件,最下面的代碼中能夠看到 vuex 暴露出的 Store 這個 API:函數

export default {
  Store,
  install,
  mapState,
  mapMutations,
  mapGetters,
  mapActions
}
複製代碼

Store

找到 Store 這一個類,挺長的一大段代碼。老辦法,所有方法摺疊不看,只看構造函數 constructor。開啓過濾之眼,過濾掉與 state 無關的代碼,最後能夠把代碼簡化成這樣:學習

constructor (options = {}) {
  const {
    state = {}
  } = options

  // init root module.
  // this also recursively registers all sub-modules
  // and collects all module getters inside this._wrappedGetters
  installModule(this, state, [], options)

  // initialize the store vm, which is responsible for the reactivity
  // (also registers _wrappedGetters as computed properties)
  resetStoreVM(this, state)
}
複製代碼

瞬間代碼少了好多,接下來只須要關注 installModuleresetStoreVM 兩個方法的實現便可。緊接着,再透露一個好消息,installModule 看了一眼,是關於 module 的初始化,等之後研究 module 再看也不遲,因此只須要研究 resetStoreVM 便可。

resetStoreVM

定位到 resetStoreVM 方法,再次過濾,其中 Vue.config.silent 去 vue 的官網上搜了一下,是取消 vue 全部的日誌與警告的功能,因此也過濾掉,剩下代碼以下:

function resetStoreVM (store, state) {
  // use a Vue instance to store the state tree
  store._vm = new Vue({
    data: { state }
  })
}
複製代碼

resetStoreVM 函數作的事情就是給 store 添加一個 _vm 屬性,並將 state 做爲一個 vue 對象的 data,最後將這個 vue 對象賦值給 _vm。因此到這裏咱們知道了 store 類的構造函數爲其添加了一個 _vm 屬性。

set 與 get

構造函數解析完畢,接下來得繼續找跟 state 相關的方法,因而找到了 setget 方法:

get state () {
  return this._vm.state
}

set state (v) {
  assert(false, `Use store.replaceState() to explicit replace store state.`)
}
複製代碼

set 方法沒什麼好說的,意思就是 store 不給你直接修改 state(但實際上是能夠修改 state 對象的屬性,先無論那麼多了)。

get 方法返回了剛剛構造函數添加的 _vm 屬性的一個 data(state)。閱讀到這裏,這下咱們應該知道爲何組件 a 修改了 state.count,組件 b 也會跟着變了吧。由於 state 就是一個新的 vue 對象裏 data 的一個屬性啊。到這裏若是還不明白,是否是要回去 vue 官網從新學習 data 啦。

這樣總算是解決了我剛開始閱讀時的疑惑了。仔細思考一下,這不就是 vue 官網非父子組件的通訊中的 bus 注入到整個應用的 vue 對象中嗎?!

總結

本篇咱們瞭解了 store 的 state,知道它是經過 new 一個新的 vue 對象 _vm 來監聽的,而這個 _vm 又是綁在 store 上的。因此經過這一系列的關係,最後咱們能在各個組件中使用到被監聽的 this.$store.state

相關文章
相關標籤/搜索