前言
接下来我们则开始要研究的是 vuex 的 store 对象。
store 对象中有一个属性叫 state。state 包含了全部的应用层级状态。应用中的各个组件若使用了 state,则会保持与同步最新的状态。state 就好比是 vue 中的 data,但它是整个应用的 data。
举个简单的例子:应用中的子组件 a 和子组件 b 用到了 state.count,两个组件是非父子关系。这时,子组件 a 修改了 state.count,子组件 b 中的 state.count 也会相应修改。
那我们就来看看,vuex 是如何在各个组件中做到监听 state 的属性的。
注:本次阅读的是 vuex 的 2.0.0 版本,源码请戳 这里。
解读
在开始阅读源码之前,我一直有一个疑惑。我在组件 a 修改了 state.count,组件 b 是怎么监听到 state.count 的改变的?难道是 store 里对 state 做了类似 object.defineproperty() 的处理。
带着疑惑,开始啦.....
从哪开始切入呢?就从 store 对象被实例化的代码中开始吧。
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)
}
复制代码
瞬间代码少了好多,接下来只需要关注 installModule
与 resetStoreVM
两个方法的实现即可。紧接着,再透露一个好消息,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 相关的方法,于是找到了 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。