Vuex 源码解析系列(二)

Vuex 源码阅读系列会分为三篇,前两篇会主要解析 Vuex 初始化中做了什么,最后一篇主要解析各种常用 API。

因为涉及代码较多,更推荐在 PC 浏览。

installModule 解析

接下来看 installModule 的实现

// installModule(this, state, [], this._modules.root)
function installModule (store, rootState, path, module, hot) {
  // 判断是否为 rootModule
  const isRoot = !path.length
  // 获取 namespace,root 没有 namespace
  // 对于 modules: {a: moduleA} 来说
  // namespace = 'a/'
  const namespace = store._modules.getNamespace(path)
  // 为 namespace 缓存 module
  if (module.namespaced) {
    store._modulesNamespaceMap[namespace] = module
  }
  // 设置 state
  if (!isRoot && !hot) {
    // 以下逻辑就是给 store.state 添加属性
    // 根据模块添加
    // state: { xxx: 1, a: {...}, b: {...} }
    const parentState = getNestedState(rootState, path.slice(0, -1))
    const moduleName = path[path.length - 1]
    store._withCommit(() => {
      Vue.set(parentState, moduleName, module.state)
    })
  }
  // 该方法其实是在重写 dispatch 和 commit 函数
  // 你是否有疑问模块中的 dispatch 和 commit
  // 是如何找到对应模块中的函数的
  // 假如模块 A 中有一个名为 add 的 mutation
  // 通过 makeLocalContext 函数,会将 add 变成
  // a/add,这样就可以找到模块 A 中对应函数了
  const local = module.context = makeLocalContext(store, namespace, path)
  // 以下几个函数遍历,都是在
  // 注册模块中的 mutation、action 和 getter
  // 假如模块 A 中有名为 add 的 mutation 函数
  // 在注册过程中会变成 a/add
  module.forEachMutation((mutation, key) => {
    const namespacedType = namespace + key
    registerMutation(store, namespacedType, mutation, local)
  })
  module.forEachAction((action, key) => {
    const type = action.root ? key : namespace + key
    const handler = action.handler || action
    registerAction(store, type, handler, local)
  })
  // 这里会生成一个 _wrappedGetters 属性
  // 用于缓存 getter,便于下次使用
  module.forEachGetter((getter, key) => {
    const namespacedType = namespace + key
    registerGetter(store, namespacedType, getter, local)
  })
  // 递归安装模块
  module.forEachChild((child, key) => {
    installModule(store, rootState, path.concat(key), child, hot)
  })
}

resetStoreVM 解析

接下来看 resetStoreVM 的实现,该属性实现了状态的响应式,并且将 _wrappedGetters 作为 computed 属性。

// resetStoreVM(this, state)
function resetStoreVM (store, state, hot) {
  const oldVm = store._vm
  // 设置 getters 属性
  store.getters = {}
  const wrappedGetters = store._wrappedGetters
  const computed = {}
  // 遍历 _wrappedGetters 属性
  forEachValue(wrappedGetters, (fn, key) => {
    // 给 computed 对象添加属性
    computed[key] = () => fn(store)
    // 重写 get 方法
    // store.getters.xx 其实是访问了
    // store._vm[xx]
    // 也就是 computed 中的属性
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key],
      enumerable: true // for local getters
    })
  })
  // 使用 Vue 来保存 state 树
  // 同时也让 state 变成响应式
  const silent = Vue.config.silent
  Vue.config.silent = true
  // 当访问 store.state 时
  // 其实是访问了 store._vm._data.$$state
  store._vm = new Vue({
    data: {
      $$state: state
    },
    computed
  })
  Vue.config.silent = silent
  // 确保只能通过 commit 的方式改变状态
  if (store.strict) {
    enableStrictMode(store)
  }
}

最后

以上是第二部分的 Vuex 源码解析,介绍了 Vuex 如何在初始化的过程创建 module 树,并且如何将 state 变为响应式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值