Appearance
installModule 不考虑命名空间
javascript
// 处理每个模块的 state、action、mutation、getter
function installModule (store, rootState, path, module, hot) {
// 第一次调用时 path是 [],module 是根模块,即 this._modules.root。
// 通过 path.length 判断是不是根模块
const isRoot = !path.length
// 对于每个模块的 state 都要实现双向数据绑定,只需要将非根模块的 state 都挂载到
// 父模块中,这里通过 Vue.set 往父模块的 state 中添加当前模块的 state 即可。
// 最后根模块的 state 中就有了所有模块的 state,将根模块的 state 设置双向数据绑
// 定即可。
if (!isRoot) {
const parentState = getNestedState(rootState, path.slice(0, -1))
const moduleName = path[path.length - 1]
// 初始化时直接赋值也行,但 registerModule 时必须 Vue.set 保证添加的 state 所有
// 层次属性的响应式,因此统一 Vue.set。
Vue.set(parentState, moduleName, module.state)
}
// local(module.context) 是一个对象,保存着当前模块的
// dispatch、commit、getters、state
const local = module.context = makeLocalContext(store, namespace, path)
// 遍历当前模块的 mutations,将每个 mutation 收集到 store._mutations 中
// store._mutations 是一个对象,里面的每个 key 是 mutation 的名字,
// 每个 value 是一个数组,数组中保存着这个名字对应的 handler
// 注意这个 hadnler 并不是我们定义的 handler,而是在 hadnler 之外包裹了一层函数
// 叫做 wrappedMutationHandler,因为我们在调用 handler 时可能传 payload
// wrappedMutationHandler 内部会把 handler 执行并修改 this 为 store
// 同时给 handler 传递两个参数当前模块的 state 和 用户传递的 payload
module.forEachMutation((mutation, key) => {
registerMutation(store, key, mutation, local)
})
// 遍历当前模块的 actions,将每个 action 收集到 store._actions 中
// store._actions 是一个对象,里面的每个 key 是 action 的名字,
// 每个 value 是一个数组,数组中保存着这个名字对应的 handler
// 注意这个 hadnler 并不是我们定义的 handler,而是在 hadnler 之外包裹了一层函数
// 叫做 wrappedActionHandler,因为我们在调用 handler 时可能传 payload
// wrappedActionHandler 内部会把 handler 执行并修改 this 为 store
// 同时给 handler 传递两个参数当前模块的 context 和 用户传递的 payload
// context 有六个属性,其中四个是 local(module.context) 的
// dispatch、commit、state、getters,另外两个是 rootState、rootGetters
// 由于 action 的可能是异步任务,还可能内部调用别的 action,因此如果 dispatch 的
// 结果不是 Promise,就通过 Promise.resolve(res) 让它是一个成功的 Promise
// 如果 store._actions[type]的长度 > 1,通过
// Promise.all(entry.map(handler => handler(payload))) 来判断是否所有 action
// 都成功,最后返回一个 Promise,只有都成功时才返回成功的 Promise。
module.forEachAction((action, key) => {
registerAction(store, key, action, local)
})
// 遍历当前模块的 getters,将每个 getter 收集到 store._wrappedGetters 中
// store._wrappedGetters 是一个对象,里面的每个 key 是 getter 的名字,
// 因为 getter 不允许重名,所以每个 value 是一个 hadnler,
// 注意这个 hadnler 并不是我们定义的 handler,而是在 hadnler 之外包裹了一层函数
// 叫做 wrappedGetter, wrappedGetter,内部会把 getter 执行同时传递四个参数
// 当前模块的 state、当前模块的 getters、根模块的 state、根模块的 getters
module.forEachGetter((getter, key) => {
registerGetter(store, key, getter, local)
})
// 遍历子模块递归调用 installModule,path 中拼接上级模块名,用于将 state 挂载到
// 上级模块中
module.forEachChild((child, key) => {
installModule(store, rootState, path.concat(key), child, hot)
})
}
function makeLocalContext (store, namespace, path) {
// dispatch 就是 store.dispath,commit 就是 store.commit
const local = {
dispatch: store.dispatch,
commit: store.commit
}
// state 就是 当前模块的 state
// 没有 namespace 时,getters 就是 store.getters
// 因为 state 和 getters 可能被修改,为了保证获取到最新的 state 和 getters,
// local 对象被劫持了
// 访问 local.state 时会返回 从 store.state 根据路径找到的结果
// 访问 local.getters 会返回 store.getters。
Object.defineProperties(local, {
getters: {
get: store.getters
},
state: {
get: () => getNestedState(store.state, path)
}
})
return local
}
function registerMutation (store, type, handler, local) {
const entry = store._mutations[type] || (store._mutations[type] = [])
entry.push(function wrappedMutationHandler (payload) {
handler.call(store, local.state, payload)
})
}
function registerAction (store, type, handler, local) {
const entry = store._actions[type] || (store._actions[type] = [])
let res = handler.call(store, {
dispatch: local.dispatch,
commit: local.commit,
getters: local.getters,
state: local.state,
rootGetters: store.getters,
rootState: store.state
}, payload)
// 默认是成功的 Promise
if (!isPromise(res)) {
res = Promise.resolve(res)
}
}
function registerGetter (store, type, rawGetter, local) {
if (store._wrappedGetters[type]) {
return
}
store._wrappedGetters[type] = function wrappedGetter (store) {
return rawGetter(
local.state, // local state
local.getters, // local getters
store.state, // root state
store.getters // root getters
)
}
}
function getNestedState (state, path) {
return path.reduce((state, key) => state[key], state)
}
class Module {
forEachChild (fn) {
forEachValue(this._children, fn)
}
forEachGetter (fn) {
if (this._rawModule.getters) {
forEachValue(this._rawModule.getters, fn)
}
}
forEachAction (fn) {
if (this._rawModule.actions) {
forEachValue(this._rawModule.actions, fn)
}
}
forEachMutation (fn) {
if (this._rawModule.mutations) {
forEachValue(this._rawModule.mutations, fn)
}
}
}