没有看过 moduleCollection 那可不行!Vuex 源码学习(四)module 与 moduleCollection
代码块和截图的区别
代码块部分希望大家按照我的引导一行行认真的读
代码的截图是希望大家能记住图中的结构与方法,下面会对整体进行一个分析,而不会一行一行的分析。
但是以后的文章会更偏向于使用代码块,希望大家喜欢。
上一章我们讲述了 ModuleCollection 类的作用,帮助我们把伪(未加工的)模块变成真正的模块,然后把每个模块按照父子与兄弟关系链接起来。那么真正的模块相比于伪(未加工的)模块多了哪些能力呢?
module 提供的方法
这是 module 暴露出来的所有方法,以及一个属性。
先看一下 constructor
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) || {}
}
模块的初始化主要是做了以下三件事情
创建_children 属性用于存放子模块
创建_rawModule 属性存储自己模块的伪(未被加工)模块时的内容
创建 state 属性存储自己模块的数据内容 每个模块都有自己的 state。
模块的初始化并没有做什么事情,模块提供的方法和属性才是它的核心,模块提供了一个 namespaced 的属性,以及很多方法,我将模块提供的方法分成两类。
先说属性
get namespaced () {
// 获取模块的 namespaced 属性 确定这个模块有没有自己的命名空间
return !!this._rawModule.namespaced
}
判断是否有命名空间有什么用?在以后设置 getters、mutation、actions 时有很大作用,以后再讲。
再说方法
模块提供的所有方法都是为了给外部的调用,这些方法没有一个是让模块在自己的内部使用的。所以我把方法划分的纬度是,按照这个方法是用于构建模块树还是用于抽取模块中的内容,
构建模块树的方法:
1.addChild:给模块添加子模块。
addChild (key, module) {
this._children[key] = module
}
这个方法实现上很简单,它是在哪里被调用的呢?大家可以翻开上一章的 moduleCollection 的内容,在 ModuleCollection 中完成模块之间的链接,就是使用这个方法给父模块添加子模块。
removeChild:移除子模块 Vuex 初始化的时候未使用,但可以给你提供灵活的处理模块的能力
removeChild (key) {
delete this._children[key]
}
getChild:获取子模块 获取子模块的意义是什么?在以后配置模块的名字时,需要获取模块的是否设置了命名空间,获取命名空间的属性模块提供了,再提供一个获取子模块就都 Ok 了
getChild (key) {
return this._children[key]
}
updateChild: 更新模块的_ra wModule 属性(更新模块的未加工前的模块内容),Vuex 中未使用
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
}
}
Vuex 在链接与整合模块的时候使用了其中两个方法,addChild、getChild。类 ModuleCollection 在链接时需要找到模块(getChild)然后给模块添加子模块(addChild)的功能,所以这两个方法是在整合模块时最重要的。
抽取模块中的内容
上面的一组方法,是为了更好的完成模块的链接,给散落的单一模块整理成一个模块树可以提供便捷的封装方法,下面要说的方法什么叫做抽取模块中的内容?将这些方法暴露给外面可以方便的去获取这个模块内的一些内容来使用。
forEachValue 是 Vuex 封装的工具方法,用于遍历对象的。
export function forEachValue (obj, fn) {
Object.keys(obj).forEach(key => fn(obj[key], key))
}
这四个方法作用:
forEachChild:遍历模块的子模块
forEachGetter:遍历模块中_rawModule.getters 这块就应该知道 _rawModule 的作用了,我把模块未加工时会有 getters 属性,存放这个模块所有的 getters 方法(vuex 的基本用法就不多讲了),然后遍历,
forEachMutation : 和 forEachGetter 类似,只是换成了遍历 mutations
forEachAction : 和 forEachGetter 类似,只是换成了遍历 actions
这四个方法就是遍历这些内容,有意义吗?
意义很大, 目前_rawModule 上这些 getters、mutations、actions 属性并不会生效,只是单纯的一个属性,如何让他们可以成为那种,被 dispatch、commit 使用的那种方法呢?先给大家一个小提示,mutations、actions 都是要被注册的,注册之前总要获取到这些内容,具体的实现方式后面的章节会详细讲述,
总结
加工后真正的 module(我们称由 Module 这个类实例化出来为真正的 module)只是缓存了一些内容,并且给外界提供了一堆方便高效的方法。这些方便高效的方法为之后的注册 action、mutation。整合 state 都起了很关键的作用。所以说 module 这个小单元为下面的代码提供了很大便利,额外思考我们对一段内容需要频繁的处理并且处理方式大同小异的时候,是不是可以像 module 一样整理成一个对象,然后给外界提供一些方法。(有一种面向对象思想)
下一章讲述 action 和 mutation 是如何调用的
我是一个应届生,最近和朋友们维护了一个公众号,内容是我们在从应届生过渡到开发这一路所踩过的坑,已经我们一步步学习的记录,如果感兴趣的朋友可以关注一下,一同加油~