Appearance
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())
}
}