vuex工作原理

898 阅读3分钟

浅析vuex的构成

vuex 引入 StateGetter 的概念对状态进行定义;使用 MutationAction对状态进行变更;引入Module对状态进行模块化分割;引入插件对状态进行快照、记录、以及追踪等;提供了mapStatemapGettersmapActionsmapMutations 辅助函数方便开发者在vm中处理store。具体构成关系如下:

浅析vuex的使用

我们只需要利用vueuse机制将 实例化后的store对象 注入vue实例即可!如下图:

Vue.use(Vuex); // 1. vue的插件机制,安装vuex
let store = new Vuex.Store({ // 2.实例化store,调用install方法
     state,
     getters,
     modules,
     mutations,
     actions,
     plugins
});
new Vue({ // 3.注入store, 挂载vue实例
    store,
    render: h=>h(app)
}).$mount('#app');

vuex的store是如何注入到组件中的?

要解答这个问题,我们先从vuex的使用表象上着手,从上面的介绍我们知道,使用vuex之前我们要对vuex进行安装!核心代码如下:

Vue.use(Vuex); // vue的插件机制,安装vuex插件

上面的代码得益于vue的插件机制,会在调用vuexinstall方法时,装载vuex! 所以我们直接关注 install方法的实现,其核心代码如下:

Vue.mixin({ beforeCreate: vuexInit });

可见,store注入 vue的实例组件的方式,是通过vuemixin机制,借助vue组件的生命周期 钩子 beforeCreate 完成的。 即 每个vue组件实例化过程中,会在 beforeCreate 钩子前调用 vuexInit 方法。下面,我们将焦点聚焦在 vuexInit 函数。 下面为 vuexInit 的核心代码!

this.$store = typeof options.store === 'function'
    ? options.store()
    : options.store

该代码的核心问题是this的指向,得益于mixin机制,this将指向 vue组件实例!最终,我们可以再 vue组件实例上获得vuexstore 对象的引用 $store!图示如下:

vuex利用了vuemixin机制,混合 beforeCreate 钩子 将store注入至vue组件实例上,并注册了 vuex store的引用属性 $store

vuex的state 和 getter 是如何映射到 各个组件实例中自动更新的?

问题剖析

该问题的核心问题是当store中的 stategetter 方式变更时,vuex如何保证各个组件实例中的数据自动更新,并update 组件!简言之,某一组件store更新时,如何通知其他组件进行数据更新,和UI更新!通过简单分析可知,问题的根本就是组件通信的问题。

浅谈组件通信

从分析可知,要解答本篇疑问,我们需要从 vue组件通信谈起! 在使用vue的过程中,需要频繁的进行组件间通信!通信的主体之间的关系可以是 父子组件,也可以是 类似 兄弟组件 或者是 无关组件 等非父子组件。 总的来说 有如下几种方式:

  1. 通过props向子组件传递数据:父 -> 子
  2. 通过事件向父组件发送消息:子 -> 父,使用$emit发送事件
  3. 父链 和 子索引:this.$parentthis.$children
  4. 依赖注入:provideinject
  5. 子组件引用: ref$refs
  6. 特性绑定:v-bind="$attrs"v-on="$listeners"
  7. event bus
  8. 利用全局变量、storagecookiequeryhash等传递数据: 非vue特性,不做赘述。
  9. 全局事件广播

主要介绍第7种,event bus
其核心设计思想是引入中央通信桥梁——中央事件总线,使各个组件只与其进行通信,达到数据同步的通信目的!如下图 组件A数据变更,通知中央事件总线,其他组件监听并接收变更的数据。

下面代码展示了在vue中使用 中央事件总线 进行组件通信:

let bus = new Vue({
     methods: {
         emit (event, ...args) {
             this.$emit(event, ...args);
         },
         on (event, callback) {
             this.$on(event, callback);
         }
     }
 });
 
 //component A
 bus.emit('updateData', data); // 发送数据给 bus。
 
 //component B
 bus.on('updateData', data => {
     // 接收 updateData事件 发送的数据信息。
 })

vue的中央事件总线的实现 简单讲就是新建了一个vue对象,借助vue对象的特性(emit on) 作为其他组件的通信桥梁,实现组件间的通信 以及数据共享!
vuexstate是借助vue的响应式data实现的。设计思想与vue中央事件总线如出一辙。

getter的实现借助了vuecomputed的特性而实现。