深入vuex原理(下)

栏目: JavaScript · 发布时间: 5年前

内容简介:在深入 vuex原理(上) 中,我们回答了 “vuex的store是如何注入到组件中的?” 的问题,下面我们继续对以下问题进行探讨!本篇文章主要讨论 "vuex的state 和 getter 是如何映射到 各个组件实例中自动更新的?" 这个问题。首先,我们对问题进行简单剖析!注:本篇文章只展示关键核心代码,一来由于篇幅原因,二来展示核心代码更容易让人理解!再者,本篇属于 vuex 高级篇,对于本篇章中 涉及的 vue 相关的机制 以及 vuex的 高级使用 等 不进行过多赘述!请自行前往官网查看!

在深入 vuex原理(上) 中,我们回答了 “vuex的store是如何注入到组件中的?” 的问题,下面我们继续对以下问题进行探讨!

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

本篇文章主要讨论 "vuex的state 和 getter 是如何映射到 各个组件实例中自动更新的?" 这个问题。首先,我们对问题进行简单剖析!

注:本篇文章只展示关键核心代码,一来由于篇幅原因,二来展示核心代码更容易让人理解!再者,本篇属于 vuex 高级篇,对于本篇章中 涉及的 vue 相关的机制 以及 vuex的 高级使用 等 不进行过多赘述!请自行前往官网查看!

准备

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

问题剖析

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

浅谈组件通信

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

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

下图展示了 上述 方案 1~6 的组件通信方式。

深入vuex原理(下)

由于 方案 8 官方已经不建议在vue2中使用,此处不做赘述;而方案9~10 不属于vue特性,而是前端通用的数据通信方案,此处也不进行赘述!如有其它方案,欢迎补充!

下面,我们主要介绍一下与本文内容息息相关的方案7,中央事件总线的解决方案!其核心设计思想是引入中央通信桥梁——中央事件总线,使各个组件只与其进行通信,达到数据同步的通信目的!如下图 组件A数据变更,通知中央事件总线,其他组件监听并接收变更的数据。

深入vuex原理(下)

下面代码展示了在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对象的特性( on) 作为其他组件的通信桥梁,实现组件间的通信 以及数据共享!

探秘原理

本部分将针对以上疑问,通过源码分析,剖析核心代码,对问题进行解答。

使用我们探讨的是state 和 getter,首先我们先来看一下在vue组件中如何方便的获取 vuex的state和getter吧!

this.$store.state.xxx;
this.$store.state.moduleA.xxx;

this.$store.getters.xxx;
this.$store.getters.moduleA.xxx;

复制代码

正如我们所知的,vuex的Store 会划分出 state 和 getters 两个数据区。getter是从store的state中派生出的状态!代码如下:

// 初始化store时,划分出 state数据区 与 getters数据区
new Vuex.Store({state, getters});
复制代码

源码分析

首先,我们先来看state。从源码中我们找到了state的get方法,如下:

get state () {
    return this._vm._data.$$state
  }

复制代码

从源码得知,在vue组件中 使用 this.$store.getters.xxx 获取 xxx 属性时,实际上是获取的 store._vm.data.$$state 对象上的同名属性。那么我们将关注点放在 _vm上。我们通过Store 的constructor 找到了处理state 和 getter的核心函数 resetStoreVM(this, state) 。其核心代码如下:

store._vm = new Vue({
    data: {
      $$state: state
    }
  })
  
复制代码

上述代码初始化了一个vue实例 _vm,由于vue的data是响应式的,所以,$$state也是响应式的,那么当我们 在一个组件实例中 对state.xxx进行 更新时,基于vue的data的响应式机制,所有相关组件的state.xxx的值都会自动更新,UI自然也会自动更新!可见,这和vue的中央事件总线 设计思想如出一辙,同样借助 vue对象特性(响应式的data)作为其他组件的通信桥梁,实现组件间的通信 以及数据共享!

总结

vuex的state是借助vue的响应式data实现的。设计思想与vue中央事件总线如出一辙!

猜测

vue中 computed从data中派生出的计算属性, vuex中 getter是从state中派生出的属性;而 vuex 中的state是借助data实现的,那么getter是否是借助computed实现的呢?

源码验证

在resetStoreVM 中可以看到 对于wrappedGetters(经过包装,收集的getters,处理细节忽略)的处理。

const computed = {};
// 处理getters
forEachValue(wrappedGetters, (fn, key) => {
    computed[key] = () => fn(store) // 将getter存储在computed上
    //this.$store.getters.XXX的时候获取的是store._vm.XXX
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key], 
      enumerable: true
    })
})
  
复制代码

上述代码,对wrappedGetters 进行处理,让getter 存储至computed对象上,下面我们关注后续computed的处理即可!

store._vm = new Vue({
    computed
  })
复制代码

上述代码将computed对象挂载至 vue实例 _vm的computed属性上,得益于vue的计算属性特性,数据的变更同样可以同步至其他相关组件上。这与我们的猜测一致!getter的实现借助了vue的computed的特性而实现!

分析至此,我们已经得出该问题的答案!


以上所述就是小编给大家介绍的《深入vuex原理(下)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Go语言学习笔记

Go语言学习笔记

雨痕 / 电子工业出版社 / 2016-6 / 89

作为时下流行的一种系统编程语言,Go 简单易学,性能很好,且支持各类主流平台。已有大量项目采用 Go 编写,这其中就包括 Docker 等明星作品,其开发和执行效率早已被证明。本书经四年多逐步完善,内容覆盖了语言、运行时、性能优化、工具链等各层面知识。且内容经大量读者反馈和校对,没有明显的缺陷和错误。上卷细致解析了语言规范相关细节,便于读者深入理解语言相关功能的使用方法和注意事项。下卷则对运行时源......一起来看看 《Go语言学习笔记》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

MD5 加密
MD5 加密

MD5 加密工具