Skip to content

Getter

使用方式

js
moduleABA.getters: {
  // ...
  doneTodosCount (state, getters) {
    return getters.doneTodos.length
  }
}

store.getters["moduleA/modueleAB/modueleABA/getters"] // -> 1

初始化阶段

遍历处理 module 中的 getters 属性,将每一个 getter 按照以其 namespaced + / + getterNameKey为 key 存储到 store._wrappedGetters[type]下。这样上面moduleA/modueleAB/modueleABA/getters就会变成 store._wrappedGetters["moduleA/modueleAB/modueleABA/getters"] = () => {}

这边根 action 一样两组不同的对象 local.state store.state

js
/**
 * 在store上注册当前getter方法
 * @param {*} store   根store
 * @param {*} type  namespace
 * @param {*} rawGetter   getter回调方法
 * @param {*} local     local context对象
 * @returns
 */
function registerGetter(store, type, rawGetter, local) {
  // 如果已存在,则报重复
  if (store._wrappedGetters[type]) {
    if (process.env.NODE_ENV !== "production") {
      console.error(`[vuex] duplicate getter key: ${type}`)
    }
    return
  }
  store._wrappedGetters[type] = function wrappedGetter(store) {
    //  执行回调方法,入参为 local.state local.getters store.state store.getters
    return rawGetter(
      local.state, // local state
      local.getters, // local getters
      store.state, // root state
      store.getters // root getters
    )
  }
}

getter 的访问

访问方式为 store.getters["moduleA/modueleAB/modueleABA/getters"] // -> 1, 其实现方法在 resetStoreVM 方法中

核心源码为:

js
function resetStoreVM(store, state, hot) {
  // bind store public getters
  store.getters = {}
  const wrappedGetters = store._wrappedGetters
  const computed = {}
  forEachValue(wrappedGetters, (fn, key) => {
    // use computed to leverage its lazy-caching mechanism
    computed[key] = () => fn(store)
    // 将 store._wrappedGetters 的所有属性 代理到 store.getters上
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key],
      enumerable: true, // for local getters
    })
  })
  // 生成一个空的Vue实例,然后将所有的getters的属性 作为计算属性 存放在 _vm上
  store._vm = new Vue({
    data: {
      $$state: state,
    },
    computed,
  })
}

可见其也是借助于 Vue 的计算属性功能 将store.getters["moduleA/modueleAB/modueleABA/getters"] 代理到 store._vm["moduleA/modueleAB/modueleABA/getters"],这样就可以使得当 state 发生变化的时候响应式触发 computed 中 getter 方法的回调

总结

  1. 其不是按照树结构存储在 store 下的,而是按照命令空间扁平化的方式通过 getNamespace() 方法生成其唯一的字符串 key 存储在 store._wrappedGetters

  2. 借助于 Vue 响应式功能将 store 的 getter 注册到 computed 属性下,从而实现 state 的跟新触发 getter 的回调功能