vuex 源码:深入 vuex 之 getter

前言

vuex 把 getter 比作是 store 的计算属性 。就像 vue 的计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值 data 发生了改变才会被重新计算。

其实,知道了 state 是 _vm 实例中的 data,那首先可以猜测 getter 就是 computed。那么,我们就来验证一下这个猜测是否是正确的。先说结论,当然是正确的啦哈哈~

注:本次阅读的是 vuex 的 2.0.0 版本,源码请戳 这里

解读

跟解读 state 一样,getter 是 store 对象的属性,所以依然从 Store 这个类开始入手。

还是开始看构造函数 constructor,发现里面并没有 getter 的代码,但有两个方法,进去后发现有相关的代码,于是代码简化为:

constructor (options = {}) {
  // and collects all module getters inside this._wrappedGetters
  installModule(this, state, [], options)

  // initialize the store vm, which is responsible for the reactivity
  // (also registers _wrappedGetters as computed properties)
  resetStoreVM(this, state)
}
复制代码

接下来的任务就是从 installModuleresetStoreVM 两个方法中找到 getter 的实现即可。

installModule

先来看 installModule。简化了代码后,发现跟 getter 相关的只有 wrapGetters 方法:

function installModule (store, rootState, path, module, hot) {
  const isRoot = !path.length
  const {
    getters
  } = module

  if (getters) {
    wrapGetters(store, getters, path)
  }
}
复制代码

进入 wrapGetters 方法,我们会发现这个方法的实现是为了拼接 store 的一个 _wrappedGetters 对象。这样拼接的目的是为了可以在需要执行 getter 里的方法时,还能传想传的参数再执行。我们暂时忽略 modulePath 与一些判断,简化代码为:

function wrapGetters (store, moduleGetters) {
  Object.keys(moduleGetters).forEach(getterKey => {
    const rawGetter = moduleGetters[getterKey]
    
    // 将 options 里的 getter 赋值到 _wrappedGetters
    // 因为 computed 的赋值就是 return 一个函数
    store._wrappedGetters[getterKey] = function wrappedGetter (store) {
      return rawGetter(
        store.state, // local state
        store.getters, // getters
        store.state // root state
      )
    }
  })
}
复制代码

resetStoreVM

专门为 store 拼接了一个 _wrappedGetters 对象有啥好处呢?别急,我们先看另一个方法 resetStoreVM,还是过滤掉与 getter 不相关的代码:

function resetStoreVM (store, state) {
  // bind store public getters
  store.getters = {}
  
  // 获取刚刚拼接的 _wrappedGetters
  const wrappedGetters = store._wrappedGetters
  
  // 开始拼接 computed
  const computed = {}
  Object.keys(wrappedGetters).forEach(key => {
    const fn = wrappedGetters[key]
    // use computed to leverage its lazy-caching mechanism
    computed[key] = () => fn(store)
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key]
    })
  })

  // use a Vue instance to store the state tree
  store._vm = new Vue({
    data: { state },
    computed
  })
}
复制代码

里面就用到了刚刚拼接的 _wrappedGetters 对象。先看方法里下面的 store._vm,我们猜测的没错吧,果然是 computed。那么上面的代码就是拼接一个 computed 对象了。以下这行代码就是拼接一个 Vue 能是识别的计算属性 computed。

computed[key] = () => fn(store)
复制代码

并使用 Object.defineProperty 对 store.getters 的 get 方法进行重写。这样,一旦访问了 this.$store.getters.count,那么 get 方法就会返回 this.$store._vm.count,也就是 _vm 的计算属性 count。

所以, store.getters 实际上就是 store._vm 的计算属性 computed

总结

之前解读了 state,再加上本篇的 getter,我们已经知道了 state 和 getter 分别对应着 store._vm 实例的 data 和 computed。所以下次再使用到 getter,我们可以把它当成 vue 的 computed 一样使用即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值