返回

Vuex 源码学习(八):揭秘模块 context 的创建及其作用

前端

从何而来?

在 Vuex 源码学习的上一篇章中,我们探究了 commit 与 dispatch 如何分别调用 mutation 与 action。然而,我们留下了几个悬念,涉及到我们有意略过的模块 context 属性。

在 installModule 函数中,为每个模块绑定了一个名为 context 的属性。接下来,我们将揭晓这个属性的庐山真面目,看看它是如何诞生的。

export function installModule (module, rootState, path, hot) {
  const isRoot = !path.length
  // 将当前模块注册到 store._modules 中
  registerModule(module, rootState, path)

  // store.modules 属性指向 store._modules
  module.namespaced = store.modules[path] && store.modules[path].namespaced

  if (module.namespaced) {
    // 模块的子模块的 path 前缀
    const childNamespace = path.join('.') + '.'

    // 创建 context
    module.context = makeLocalContext(module, rootState, path)
  } else {
    // 根模块的 context
    const parentNamespace = path.length ? path.join('.') + '.' : ''
    module.context = makeLocalContext(store, rootState, parentNamespace)
  }

神秘面纱

1. 剖析 context 的生成

context 的生成由 makeLocalContext 函数负责。

export const makeLocalContext = (module, rootState, path) => {
  const normalizedPath = path.reduce((memo, key) => {
    memo[key] = true
    return memo
  }, {})

  // 创建 context 对象
  const local = {
    // store 的 getter
    getters: makeLocalGetters(module, rootState, path),
    // store 的 action
    dispatch: makeLocalDispatch(module, rootState),
    // store 的 commit
    commit: makeLocalCommit(module, rootState),
    // 模块的状态
    state: vuexProxy(module.state, path),
    // 模块的命名空间
    rootGetters: module.context ? getRootGetters(module.context) : {}
  }

  // 记住,在 module.namespaced 为 true 的情况下,module.context 才会存在
  if (module.namespaced) {
    local.namespace = path.join('.')
  }

  return local
}

2. context 的宝藏

通过细细品读 makeLocalContext 的代码,我们可以窥探到 context 的本质和意义。

  • getters :模块内的 getter 函数,负责从模块状态中提取数据。
  • dispatch :模块内的 action 函数,负责执行异步操作和状态变更。
  • commit :模块内的 mutation 函数,负责直接修改模块状态。
  • state :模块的状态,可以使用 vuexProxy 进行响应式代理。
  • rootGetters :根模块的 getter 函数,用于访问根模块的状态。
  • namespace (可选):模块的命名空间,仅在 namespaced 为 true 时存在。

大显身手

context 在 Vuex 生态系统中扮演着举足轻重的角色。

1. 动作先行:dispatch 披挂上阵

action 函数是 Vuex 中执行异步操作和状态变更的主要途径,它们被封装在 context.dispatch 中。当我们调用 context.dispatch 时,就会触发相应 action 的执行,从而实现异步操作或状态更新。

2. 提交改变:commit 一锤定音

mutation 函数是 Vuex 中直接修改模块状态的唯一途径,它们被封装在 context.commit 中。当我们调用 context.commit 时,就会触发相应 mutation 的执行,从而直接更新模块状态。

3. 洞察全局:getters 尽览全貌

getter 函数是 Vuex 中从模块状态中提取数据的手段,它们被封装在 context.getters 中。当我们调用 context.getters 时,就可以访问 getter 函数并获取所需数据。

4. 触类旁通:rootGetters 跨界取数

rootGetters 是 Vuex 中访问根模块 getter 函数的途径,它们被封装在 context.rootGetters 中。当我们调用 context.rootGetters 时,就可以访问根模块的 getter 函数并获取根模块的状态数据。

总结

Vuex 模块的 context 属性是模块与 store 交互的桥梁,它封装了模块内的 getters、dispatch、commit、state、rootGetters 和 namespace 等属性。这些属性共同构成了模块的运行环境,使模块能够与 store 进行高效通信和数据共享。

理解了 context 的创建过程和作用,我们才能更深入地理解 Vuex 模块的工作原理,从而更好地利用 Vuex 管理复杂应用的状态。