“ 我们知道,vuex是一个专门为vue.js设计的状态管理器。它可以集中存储所有组件的状态,让兄弟组件或多层嵌套组件之间的传值变得简单。vuex以全局单例模式管理着所有组件的状态和一些触发状态变化的行为,本篇从源码上详解vuex是如何设计这个store单例,也就是store类实例化的过程。”
下面看一个最简单的例子:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
它最终形成的初始化的store实例对象如下图:
图1
可以看到形成的store对象中保存了commit、dispatch两个方法和getters、actions、mutations、modules、modulesNamespaceMap等等属性。下面我们看一下vuex是如何定义这些属性与方法的。
看一下store构造函数,它接收一个对象参数,里面包含actions、getters、state、mutations、modules等Vuex的核心概念。
export class Store {
constructor (options = {}) {
// Auto install if it is not done yet and `window` has `Vue`.
// To allow users to avoid auto-installation in some cases,
// this code should be placed here. See #731
if (!Vue && typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
// ...
const {
plugins = [],
strict = false
} = options
// store internal state
this._committing = false
this._actions = Object.create(null)
this._actionSubscribers = [] // 订阅actions变化的订阅者
this._mutations = Object.create(null)
this._wrappedGetters = Object.create(null)
this._modules = new ModuleCollection(options) // 初始化modules。构建一个modules树。
this._modulesNamespaceMap = Object.create(null)
this._subscribers = [] // 订阅mutations变化的订阅者
this._watcherVM = new Vue()
this._makeLocalGettersCache = Object.create(null)
// bind commit and dispatch to self
const store = this
const { dispatch, commit } = this
this.dispatch = function boundDispatch (type, payload) {
return dispatch.call(store, type, payload)
} // 执行this.dispatch时,保证dispatch上下文是store
this.commit = function boundCommit (type, payload, options) {
return commit.call(store, type, payload, options)
}
// strict mode
this.strict = strict
const state = this._modules.root.state
// 安装模块
installModule(this, state, [], this._modules.root)
// getters和state建立依赖关系,变成响应式
resetStoreVM(this, state)
// apply plugins
plugins.forEach(plugin => plugin(this))
const useDevtools = options.devtools !== undefined ? options.devtools : Vue.config.devtools
if (useDevtools) {
devtoolPlugin(this)
}
}
...
}
以上构造函数逻辑,我们会重点关注到三个点:
this._modules = new ModuleCollection(options):modules初始化模块,形成一棵modules树,最终会存储在图1的_modules属性中.
installModule(this, state, [], this._modules.root):安装模块
resetStoreVM resetStoreVM(this, state):初始化store._vm
初始化模块
假设我们定义了下面这个store,这个store中包含了一个根模块和两个子模块moduleA和moduleB。
const moduleA = {
namespace: true,
state: { c: 2 },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { d: 4 },
mutations: { ... },
actions: { ... },
getters: { ... },
}
const store = new Vuex.Store({
modules: {
a: moduleA,