vuex 源码分析(4)—— resetStoreVM 初始化store的VM

532 阅读1分钟

util相关工具方法

  1. partial方法,返回只保留闭包环境中的参数的函数。
export function partial (fn, arg) {
  return function () {
    return fn(arg)
  }
}

相关参数介绍

  1. store:指store实例
  2. state:根模块的state对象(this._modules.root.state)
  3. hot:布尔值,用于控制热重载

resetStoreVM 解读

resetStoreVM 初始化 store 的 vm,它负责响应性(也将 _wrappedGetters 注册为计算属性)。

function resetStoreVM(store, state, hot) {
  // 存储store的vm
  const oldVm = store._vm
  // 定义实例的getters对象,以便存储getter
  store.getters = {}
  //重置本地getters缓存
  store._makeLocalGettersCache = Object.create(null)
  const wrappedGetters = store._wrappedGetters
  const computed = {}
  
  // 遍历wrappedGetters
  forEachValue(wrappedGetters, (fn, key) => {
    // 若是直接使用内联函数会导致保存oldVm的闭包,所以源码中定义了partial函数,
    // 用来返回只保留闭包环境中的参数的函数。使用computed,是为利用其惰性缓存机制。
    computed[key] = partial(fn, store)
    
    // 将wrappedGetters中的getter函数名定义到store.getters的对象上。
    // 这使得我们可以通过属性形式(例如:store.getters.evenOrOdd)进行访问。
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key],
      enumerable: true
    })
  })
  
  // 创建Vue实例前,设置Vue.config.silent = true,是为防止用户添加了一些时髦的
  // 全局mixins而出现日志与警告。创建完成后,则设置回原来的值。
  const silent = Vue.config.silent
  Vue.config.silent = true
  store._vm = new Vue({
    data: {
      $$state: state // 使用Vue实例存储状态树
    },
    
    // 将定义的computed变量当做vue的computed属性,以实现getter的返回值会根据它的依赖
    // 被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
    
    // computed中的属性会被添加到store._vm上,这也是为何在给store.getters对象
    // 定义属性时,设置此属性的get函数返回store._vm[key]的原因
    computed
  })
  
  Vue.config.silent = silent

  // 判断是否启用严格模式
  if (store.strict) {
    enableStrictMode(store)
  }

  if (oldVm) {
    if (hot) {
      // 对所有订阅的观察者发送变更,强制getter重新评估,以便进行热重重载。
      store._withCommit(() => {
        oldVm._data.$$state = null
      })
    }
    // 销毁旧实例
    Vue.nextTick(() => oldVm.$destroy())
  }
}

关于 enableStrictMode 和 _withCommit 方法的作用,我在上一篇中已有介绍,有疑惑的同学可以去看看。

结束语

resetStoreVM 的源码并不复杂,它主要是初始化store实例的vm。唯一的难点可能是:让 getter 在通过属性访问时作为 Vue 的响应式系统的一部分缓存其中。为此,给出我个人的两点建议:

  1. 认真阅读vuex官方文档并会使用vuex。

  2. 阅读Vue中有关computed的源码