Appearance
ModuleCollection
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时, store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成 模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套 子模块。ModuleCollection 用于将用户的模块配置项转化为树形结构。用户配置:
javascript
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})javascript
class ModuleCollection {
constructor (rawRootModule) {
// 构造器中调用 register 注册模块,register 接收参数 path 和 rawModule
// path 数组表示当前模块路径,用于表示模块之间的层级关系。第一次调用时传的 path
// 是空数组,代表根模块。
// - ['a'] 就是 a 模块
// - ['a', 'b'] 就是 a 模块下的 b 模块,
// rawModule 就是我们写的当前模块的配置项对象,是还没有处理的。
// 我们通过 Module 类将配置项对象处理成一个新对象 newModule,newModule 中有这些
// 属性:
// - _children,是一个对象,存储着当前模块的子模块,这些子模块也都经过了
// Module 类处理
// - _rawModule,表示未经处理的当前模块,即 rawModule,我们写的当前模块的配置项
// - state,表示当前模块的状态,即 rawModule.state
// newModule 需要挂载到 parent._children 中,而我们可以通过 path 中的倒数第二项
// 来找到 parent
this.register([], rawRootModule)
}
register (path, rawModule) {
const newModule = new Module(rawModule, runtime)
if (path.length === 0) {
// 第一次调用 register,将生成的 newModule 挂载到 _modules.root 上,
// _modules 就是 new ModuleCollection 的实例,_modules 最终会挂载到 store 上。
this.root = newModule
} else {
// 后续调用 register,将生成的 newModule 挂载到 parent._children 上
// - 对于 ['a'] 来说父模块就是根模块,即 this.root
// a 模块生成的 newModule 会挂载到 this.root._children 上
// - 对于['a', 'b']来说父模块就是 a 模块,
// b 模块生成的 newModule 会挂载到 this.root._children.a._children 上
// 因此先 path.slice(0, -1) 取出上级模块,通过 reduce 完成逐级查找
// 找到 parent 后将 newModule 挂载到 parent._children 中,挂载的子模块名就是
// path 数组的最后一项。
const parent = this.get(path.slice(0, -1))
parent.addChild(path[path.length - 1], newModule)
}
// register nested modules
if (rawModule.modules) {
// 根模块处理完后遍历 rawModule.modules,递归调用 register 将子模块通过
// Module 类处理生成 newModule 并挂载到 parent._children 中。
// 需要通过 path 倒数第二项找到 parent,因此调用 register 时的 path 参数
// 是当前 path 数组拼接上子模块的名字的结果。
forEachValue(rawModule.modules, (rawChildModule, key) => {
this.register(path.concat(key), rawChildModule)
})
}
}
get (path) {
return path.reduce((module, key) => {
return module.getChild(key)
}, this.root)
}
}
class Module {
constructor (rawModule, runtime) {
this.runtime = runtime
// 子模块
this._children = Object.create(null)
// 用户配置
this._rawModule = rawModule
const rawState = rawModule.state
this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}
}
addChild (key, module) {
this._children[key] = module
}
}