Vuex源码解析(三) 注册模块 installModule 做了什么

113 阅读2分钟

installModule

installModule是在Store类中constructor中执行的方法,主要作用就是对 Vuex 中的 module 进行模块注册,并且通过 plugins.forEach(plugin => plugin(this)) 进行对模块的应用

  • 根据路径长度判断是否为根模块,获取命名空间,判断当前模块是否有命名空间,如果有则将其加入 _modulesNamespaceMap 中
  • 判断是否为根模块,如果不是则先获取父模块再获取子模块,用 Vue.set 将模块添加到父模块中,使其为响应式的数据
  • 获取上下文环境信息
  • 依次遍历 getters 、 mutation 、 action 将其分别加入对应的收集队列数组中
  • 判断是是否还有 modules 如果则遍历执行 installModule 完成深度遍历 module
/** * 
安装模块 
* @param {Store} store store 实例 
* @param {Store.state} rootState 根 module state 
* @param {Array<String>[]} path 模块路径
* @param {Module} module 注册的模块实例 
* @param {Boolean} hot 
*/

拆分 路径长度--模块

  // 判断 路径是不是根模块
  const isRoot = !path.length
  // 通过 getNamespace 来判断是否为根数组
  const namespace = store._modules.getNamespace(path)
  // 用户设置了 命名空间 就把 module 赋值给 _modulesNamespaceMap 的命名
  // _modulesNamespaceMap 
  // 收集模块命名空间 用以完成 根据模块区分 state mutation 等功能的 { moduleName : Module }
  if (module.namespaced) {
    store._modulesNamespaceMap[namespace] = module
  }
  // 不是根模块
  // 先获取父模块再获取子模块,用 Vue.set 将模块添加到父模块中,使其为响应式的数据
  if (!isRoot && !hot) {
    // parentState 删除最后一位
    const parentState = getNestedState(rootState, path.slice(0, -1))
    // 对应取 moduleName
    const moduleName = path[path.length - 1]
    store._withCommit(() => {
      Vue.set(parentState, moduleName, module.state)
    })
  }

getNamespace 函数

作用: getNamespace这个函数,就是从根节点开始,reduce寻找子节点,如果子节点有namespace,则把它的key拼接出来,最后返回拼接完整的 image.png

拆分 获取上下文环境信息

  const local = module.context = makeLocalContext(store, namespace, path)

makeLocalContext 函数

function makeLocalContext (store, namespace, path) {
  const noNamespace = namespace === ''

  const local = {
    dispatch: noNamespace ? store.dispatch : (_type, _payload, _options) => {
      const args = unifyObjectStyle(_type, _payload, _options)
      const { payload, options } = args
      let { type } = args

      if (!options || !options.root) {
        type = namespace + type
        return
      }

      return store.dispatch(type, payload)
    },

    commit: noNamespace ? store.commit : (_type, _payload, _options) => {
      const args = unifyObjectStyle(_type, _payload, _options)
      const { payload, options } = args
      let { type } = args

      if (!options || !options.root) {
        type = namespace + type
        return
      }

      store.commit(type, payload, options)
    }
  }

  Object.defineProperties(local, {
    getters: {
      get: noNamespace
        ? () => store.getters
        : () => makeLocalGetters(store, namespace)
    },
    state: {
      get: () => getNestedState(store.state, path)
    }
  })

  return local
}

拆分 依次遍历 getters、mutation、action 将其分别加入对应的收集队列数组中

把对应模块的对应getters、mutation、action放入收集数组中

mutation

  module.forEachMutation((mutation, key) => {
    const namespacedType = namespace + key
    registerMutation(store, namespacedType, mutation, local)
  })

action

  module.forEachAction((action, key) => {
    const type = action.root ? key : namespace + key
    const handler = action.handler || action
    registerAction(store, type, handler, local)
  })

getters

  module.forEachGetter((getter, key) => {
    const namespacedType = namespace + key
    registerGetter(store, namespacedType, getter, local)
  })

拆分 判断是是否还有 modules 如果则遍历执行 installModule 完成深度遍历 module

重新执行 installModule

  module.forEachChild((child, key) => {
    installModule(store, rootState, path.concat(key), child, hot)
  })