欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Vuex中modules的初始化过程分析

程序员文章站 2022-04-24 09:49:17
...

modules作用

  • Store作为一个数据“仓库”,存储数据,若应用变得复杂要处理的数据过多,全部放到一个state下就很麻烦。
  • modules就是将store拆分成众多具有完整结构的“子仓库“,每个module也可以添加子module,从而形成一个树状结构。方便管理数据。
  • 最外层的module可以理解为根 rootModule

modules的初始化

关键点
  1. this._modules = new ModuleCollection(options) //Store中的_modules是modules集合
  2. module_collection中定义register()方法来构建modules结构
  3. installModule(this, state, [], this._modules.root)// 初始化rootModule、注册所有子module
  4. makeLocalContext() // 重写dispatch和commit方法,利用namespace拼接type重新得到新type值(类似于绝对路径)
  5. resetStoreVM() // 将state成为响应式对象

建立模块的结构

register (path, rawModule, runtime = true) {
    if (process.env.NODE_ENV !== 'production') {
      assertRawModule(path, rawModule)
    }
    const newModule = new Module(rawModule, runtime)  //新module实例  rawModule是配置项
    if (path.length === 0) {   
      this.root = newModule   //拿到根 rootModule
    } else {
      const parent = this.get(path.slice(0, -1))
      parent.addChild(path[path.length - 1], newModule) //添加子module
    }
    // register nested modules
    if (rawModule.modules) {//如果当前module中配置了子module 则遍历并逐一注册
      forEachValue(rawModule.modules, (rawChildModule, key) => {
        this.register(path.concat(key), rawChildModule, runtime)
      })
    }
  }

得到的modules对象
Vuex中modules的初始化过程分析

安装模块

/**
	@param store 当前Store的实例
	@param rootState   modules集合中根模块root的state数据
	@param path  根模块的path为空 其他为key值
	@param  module对象
**/
function installModule (store, rootState, path, module, hot) {
  const isRoot = !path.length
  const namespace = store._modules.getNamespace(path) //根据path构造namespace  =>  key+‘/’

  // register in namespace map
  if (module.namespaced) {
    if (store._modulesNamespaceMap[namespace] && process.env.NODE_ENV !== 'production') {
      console.error(`[vuex] duplicate namespace ${namespace} for the namespaced module ${path.join('/')}`)
    }
    store._modulesNamespaceMap[namespace] = module
  }

  // set state
  if (!isRoot && !hot) {
    const parentState = getNestedState(rootState, path.slice(0, -1))
    const moduleName = path[path.length - 1]
    store._withCommit(() => {
      if (process.env.NODE_ENV !== 'production') {
        if (moduleName in parentState) {
          console.warn(
            `[vuex] state field "${moduleName}" was overridden by a module with the same name at "${path.join('.')}"`
          )
        }
      }
      Vue.set(parentState, moduleName, module.state)
    })
  }
  const local = module.context = makeLocalContext(store, namespace, path)//当前module的局部数据
  module.forEachMutation((mutation, key) => {
    const namespacedType = namespace + key
    registerMutation(store, namespacedType, mutation, local) //注册mutation
  })
  module.forEachAction((action, key) => {
    const type = action.root ? key : namespace + key
    const handler = action.handler || action
    registerAction(store, type, handler, local)//注册action
  })
  module.forEachGetter((getter, key) => {
    const namespacedType = namespace + key
    registerGetter(store, namespacedType, getter, local)//注册getter
  module.forEachChild((child, key) => {//递归处理子模块
    installModule(store, rootState, path.concat(key), child, hot)
  })
}

resetStoreVM() 将state生成为响应式对象

function resetStoreVM (store, state, hot) {
  const oldVm = store._vm
  // bind store public getters
  store.getters = {}
  // reset local getters cache
  store._makeLocalGettersCache = Object.create(null)
  const wrappedGetters = store._wrappedGetters
  const computed = {}
  forEachValue(wrappedGetters, (fn, key) => {
    // use computed to leverage its lazy-caching mechanism
    // direct inline function use will lead to closure preserving oldVm.
    // using partial to return function with only arguments preserved in closure environment.
    computed[key] = partial(fn, store)
    Object.defineProperty(store.getters, key, {//当我们访问store的getters时,会调用store._vm
      get: () => store._vm[key],
      enumerable: true // for local getters
    })
  })

  // use a Vue instance to store the state tree
  // suppress warnings just in case the user has added
  // some funky global mixins
  const silent = Vue.config.silent
  Vue.config.silent = true
  store._vm = new Vue({  //使用一个Vue实例 $$state为响应式对象,值就原state
    data: {
      $$state: state
    },
    computed
  })
 ....
}
 get state () {
    return this._vm._data.$$state 
  }
相关标签: Vuex Vue