Skip to content

registerModule

javascript
// this._modules.root._children 中添加 b 模块
this.$store.registerModule(['b'], { 
  state: {
    foo: 'foo'
  }
})

// 先有 b 模块, 才能在 this._modules.root._children.b._children 中添加 c 模块
this.$store.registerModule(['b', 'c'], { 
  state: {
    foo: 'foo'
  }
})
javascript
registerModule (path, rawModule, options = {}) {
  // 如果路径是字符串,包装成数组
  if (typeof path === 'string') path = [path]

  if (__DEV__) {
    assert(Array.isArray(path), `module path must be a string or an Array.`)
    assert(path.length > 0, 'cannot register the root module by using registerModule.')
  }

  // 通过 register 将 rawModule 生成的 newModule 挂载到 parent._children 中,
  // 再调用 installModule 进行模块安装即可,由于 state 实现了双向数据绑定,因此新
  // 模块的 state 是响应式的。但是新模块的 getter 是在 resetStoreVM 内安装上的
  // 因此需要调用 resetStoreVM 更新 getter,使得新模块的 getter 也能生效
  this._modules.register(path, rawModule)
  installModule(this, this.state, path, this._modules.get(path), options.preserveState)
  // reset store to update getters...
  resetStoreVM(this, this.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, {
      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({
    data: {
      // 实现 state 响应式,$ 开头的属性不会代理到实例上
      // 但是会挂载到 _data 上, 减少了一次代理
      $$state: state
    },
    // 实现 getter
    computed
  })
  Vue.config.silent = silent

  // enable strict mode for new vm
  if (store.strict) {
    enableStrictMode(store)
  }

  if (oldVm) {
    if (hot) {
      // dispatch changes in all subscribed watchers
      // to force getter re-evaluation for hot reloading.
      store._withCommit(() => {
        oldVm._data.$$state = null
      })
    }
    Vue.nextTick(() => oldVm.$destroy())
  }
}