Vuex源码学习(五)加工后的module

366 阅读5分钟

没有看过moduleCollection那可不行!Vuex源码学习(四)module与moduleCollection

感谢提出代码块和截图建议的小伙伴

代码块和截图的区别:

  1. 代码块部分希望大家按照我的引导一行行认真的读
  2. 代码的截图是希望大家能记住图中的结构,下面会对整体进行一个分析,而不会一行一行的分析。

但是以后的文章会更偏向于使用代码块,希望大家喜欢。

上一章我们讲述了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) || {}
}

模块的初始化主要是做了以下三件事情

  1. 创建_children属性用于存放子模块
  2. 创建_rawModule属性存储自己模块的伪(未被加工)模块时的内容
  3. 创建state属性存储自己模块的数据内容 每个模块都有自己的state。

模块的初始化并没有做什么事情,模块提供的方法和属性才是它的核心, 模块提供了一个namespaced的属性,以及很多方法,我将模块提供的方法分成两类。

先说属性

get namespaced () {
    // 获取模块的namespaced属性 确定这个模块有没有自己的命名空间
    return !!this._rawModule.namespaced
}

判断是否有命名空间有什么用?在以后设置getters、mutation、actions时有很大作用,以后再讲。

再说方法

模块提供的所有方法都是为了给外部的调用,这些方法没有一个是让模块在自己的内部使用的。所以我把方法划分的纬度是,按照这个方法是用于构建模块树还是用于抽取模块中的内容

构建模块树的方法:

1.addChild:给模块添加子模块。

addChild (key, module) {
    this._children[key] = module
}

这个方法实现上很简单,它是在哪里被调用的呢?大家可以翻开上一章的moduleCollection的内容,在ModuleCollection中完成模块之间的链接,就是使用这个方法给父模块添加子模块。 2. removeChild:移除子模块 Vuex初始化的时候未使用,但可以给你提供灵活的处理模块的能力

removeChild (key) {
    delete this._children[key]
}
  1. getChild:获取子模块 获取子模块的意义是什么?在以后配置模块的名字时,需要获取模块的是否设置了命名空间,获取命名空间的属性模块提供了,再提供一个获取子模块就都Ok了
getChild (key) {
    return this._children[key]
}
  1. 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))
}

这四个方法作用:

  1. forEachChild : 遍历模块的子模块
  2. forEachGetter : 遍历模块中_rawModule.getters 这块就应该知道 _rawModule的作用了,我把模块未加工时会有getters属性,存放这个模块所有的getters方法(vuex的基本用法就不多讲了),然后遍历,
  3. forEachMutation : 和forEachGetter类似,只是换成了遍历mutations
  4. forEachAction : 和forEachGetter类似,只是换成了遍历actions

这四个方法就是遍历这些内容,有意义吗?

意义很大,目前_rawModule上这些getters、mutations、actions属性并不会生效,只是单纯的一个属性,如何让他们可以成为那种,被dispatch、commit使用的那种方法呢?先给大家一个小提示,mutations、actions都是要被注册的,注册之前总要获取到这些内容,具体的实现方式后面的章节会详细讲述,

总结

加工后真正的module(我们称由Module这个类实例化出来为真正的module)只是缓存了一些内容,并且给外界提供了一堆方便高效的方法。这些方便高效的方法为之后的注册action、mutation。整合state都起了很关键的作用。所以说module这个小单元为下面的代码提供了很大便利, 额外思考我们对一段内容需要频繁的处理并且处理方式大同小异的时候,是不是可以像module一样整理成一个对象,然后给外界提供一些方法。(有一种面向对象思想)

下一章讲述action和mutation是如何调用的

我是一个应届生,最近和朋友们维护了一个公众号,内容是我们在从应届生过渡到开发这一路所踩过的坑,已经我们一步步学习的记录,如果感兴趣的朋友可以关注一下,一同加油~

个人公众号:咸鱼正翻身