Skip to content

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