Vuex 的原理

疑问 1:Vuex 的 store 是如何挂载注入到组件中的?

1. 在 vue 项目中先安装 vuex

npm install vuex --save

2. 利用 vue 的插件机制

使用 Vue.use(vuex) 时,会调用 vuex 的 install 方法装载 vuex。install 方法中的 applyMixin 方法使用 vue 的混入机制(mixin),在 vue 的生命周期 beforeCreate 钩子前混入 vuexInit 方法。

// 简化版 install
function install(Vue) {
  Vue.mixin({
    beforeCreate: vuexInit
  })
}

function vuexInit() {
  const options = this.$options
  if (options.store) {
    // 根实例:直接把 store 挂到 this 上
    this.$store = options.store
  } else if (options.parent && options.parent.$store) {
    // 子组件:继承父组件的 $store 引用
    this.$store = options.parent.$store
  }
}

分析源码可以知道,vuex 利用 vue 的 mixin 混入机制,在 beforeCreate 钩子前混入 vuexInit 方法。vuexInit 方法实现了 store 注入 vue 组件实例,并注册了 vuex store 的引用属性 $store,让所有组件都能通过 this.$store 访问 store。

疑问 2:vuex 的 state 和 getters 是如何映射到各个组件实例中响应式更新状态?

从源码可以看出,Vuex 的 state 状态是响应式,借助了 vue 的 data 是响应式 —— 将 state 存入 vue 实例组件的 data 中。Vuex 的 getters 则是借助 vue 的计算属性(computed)实现数据实时监听。

// 简化版:state 通过响应式 data 实现
function resetStoreVM(store, state) {
  store._vm = new Vue({
    data: { $$state: state },
    computed
  })
  // 代理 getters
  Object.keys(store.getters).forEach(key => {
    Object.defineProperty(store, key, {
      get: () => store._vm[key]
    })
  })
}

补充:Vuex 5 / Pinia 的实现思路则改为:state 通过 reactive / ref 暴露给组件,getters 就是普通的 computed,不再依赖"挂在 data 上"这种取巧实现,类型推导也更好。

来源整理自:vue3js.cn 面试官系列