接下來咱們則開始要研究的是 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 這一個類,挺長的一大段代碼。老辦法,所有方法摺疊不看,只看構造函數 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)
}
複製代碼
瞬間代碼少了好多,接下來只須要關注 installModule
與 resetStoreVM
兩個方法的實現便可。緊接着,再透露一個好消息,installModule
看了一眼,是關於 module 的初始化,等之後研究 module
再看也不遲,因此只須要研究 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 屬性。
構造函數解析完畢,接下來得繼續找跟 state 相關的方法,因而找到了 set
和 get
方法:
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。