Vuex@next源码解析 - module篇
前言 🔗
本篇主要写Vuex
中模块最基本的的一个单位,Module
– 模块对象
module.js
🔗
export default class Module {
constructor (rawModule, runtime) {}
get namespaced () {}
addChild (key, module) {}
removeChild (key) {}
getChild (key) {}
hasChild (key) {}
update (rawModule) {}
forEachChild (fn) {}
forEachGetter (fn) {}
forEachAction (fn) {}
forEachMutation (fn) {}
}
不用因为这么多方法感到退却,因为其实这些方法都是一些非常简单的方法,放下心往👇看就完事~
constructor
构造器函数addChild
添加一个子模块Module
对象removeChild
移除一个子模块Module
对象getChild
得到一个子模块Module
对象hasChild
是否拥有一个子模块Module
对象update
更新本模块forEachChild
遍历每一个子模块forEachGetter
遍历本模块每一个getter
forEachAction
遍历本模块每一个action
forEachMutation
遍历本模块每一个mutation
看起来很多,其实对于xxxChild
这几个方法,颇有点增删改查的味道😂
后四个forEachXXX
函数很明显为遍历函数
constructor
🔗
// Base data struct for store's module, package with some attribute and method
export default class Module {
constructor (rawModule, runtime) {
this.runtime = runtime
// Store some children item
this._children = Object.create(null)
// Store the origin module object which passed by programmer
this._rawModule = rawModule
const rawState = rawModule.state
// Store the origin module's state
this.state = (typeof rawState === 'function' ? rawState() : rawState) || {}
}
}
构造器函数表明了将会往对象上挂载什么属性
this.runtime
表示是否是运行时注册的模块,前面说到的注册根root
模块时
在ModuleCollection
的构造器中执行了this.register([], rawRootModule, false)
这里第三个参数为false
也就表明了根模块是不可以卸载的
this._children
本模块包含的子Module
对象
this._rawModule
用于创建模块的参数(就是用于传进来的options
),比如现在有如下store
const store = createStore({
state: {
val: 24
},
modules: {
m1: {
state: {
val: 124
}
}
}
})
那么对于根root
和m1
,他们的_rawModule
,应该是这个传入的配置对象什么部分?
可能有人会认为都是整个配置对象,但其实不是,因为在ModuleCollection
类中的register
方法中
// register nested modules
if (rawModule.modules) {
forEachValue(rawModule.modules, (rawChildModule, key) => {
this.register(path.concat(key), rawChildModule, runtime)
})
}
这里通过工具函数forEachValue
来来遍历传入的配置参数的modules
(如果存在的情况下),每次回调的rawChildModule
为本模块的一个配置对象
比如此时遍历到了modules
下的m1
,此时两者分别为
rawChildModule = {
state:{
val: 124
}
}
key = 'm1'
那么对于m1
,他的_rawModule
和rawChildModule
一样,就为
_rawModule = {
state:{
val: 124
}
}
而对于根root
模块,他的_rawModule
,就是整个传进来的参数对象
_rawModule = {
state: {
val: 24
},
modules: {
m1: {
state: {
val: 124
}
}
}
}
我们可以在控制台展开看看
发现基本符合预期,但是根root
模块的state
是合并的,在这个文件中并没有相关的操作,哪又是在进行合并的呢?
没错,之前store
篇说过,是store.js
文件中的installModule
方法
在Store
类的构造器函数中,调用了installModule
,如下
const state = this._modules.root.state
installModule(this, state, [], this._modules.root)
然后在installModule
中,有一段判断
// set state
if (!isRoot && !hot) {
const parentState = getNestedState(rootState, path.slice(0, -1))
const moduleName = path[path.length - 1]
store._withCommit(() => {
if (__DEV__) {
if (moduleName in parentState) {
console.warn(
`[vuex] state field "${moduleName}" was overridden by a module with the same name at "${path.join('.')}"`
)
}
}
// 挂载state
parentState[moduleName] = module.state
})
}
此时的rootState
就是this._modules.root.state
也就是非根模块的时候,通过getNestedState
取到父模块,然后把当前模块的state
挂载到父模块的state
上
this.state
也就是本模块的状态,通过_rawModule.state
来获取
这里做了个判断,也就是我们传入的state
属性不一定是要一个对象,也可以是一个函数返回一个对象
addChild
🔗
export default class Module {
addChild (key, module) {
this._children[key] = module
}
}
非常简单,我觉得初学者都能看懂🤣,就是往_children
属性上挂载上传入的Module
对象而已
removeChild
🔗
export default class Module {
removeChild (key) {
delete this._children[key]
}
}
通过delete
删除对应key
的Module
对象
getChild
🔗
export default class Module {
getChild (key) {
return this._children[key]
}
}
通过_children
属性返回对应的Module
对象
hasModule
🔗
export default class Module {
hasChild (key) {
return key in this._children
}
}
通过in
操作符号判断模块名key
是否存在_children
属性中
update
🔗
export default class Module {
update (rawModule) {
this._rawModule.namespaced = rawModule.namespaced
if (rawModule.actions) {
this._rawModule.actions = rawModule.actions
}
if (rawModule.mutations) {
this._rawModule.mutations = rawModule.mutations
}
if (rawModule.getters) {
this._rawModule.getters = rawModule.getters
}
}
}
通过传入的rawModule
配置来更新本模块的_rawModule
可以看到,覆盖了namespaced
,getters
,mutations
,actions
但是没有覆盖state
!,没有覆盖state
!!,没有覆盖state
!!!
重要的话讲三遍好吧,这个API可以追溯到store.hotUpdate
这个方法上,热更新时用到,可以不用太在意
forEachXXX 🔗
export default class Module {
forEachChild (fn) {
forEachValue(this._children, fn)
}
forEachGetter (fn) {
if (this._rawModule.getters) {
forEachValue(this._rawModule.getters, fn)
}
}
forEachAction (fn) {
if (this._rawModule.actions) {
forEachValue(this._rawModule.actions, fn)
}
}
forEachMutation (fn) {
if (this._rawModule.mutations) {
forEachValue(this._rawModule.mutations, fn)
}
}
}
这四个函数非常简单,依赖了工具函数forEachValue
,
每个函数对特定的对象进行属性以及对应值的遍历
后记 🔗
这个文件写完基本上核心代码就写完了
接下来会整体改进这几篇文章的细节,使大家更容易懂