Vue3 Reactive响应式原理逻辑详解

作者:??Liqiuyue???? 时间:2024-05-03 15:11:28 

前言

本篇文章主要讲解vue响应式原理的逻辑,也就是vue怎么从最开始一步步推导出响应式的结构框架。 先从头构建一个简单函数推导出Vue3的Reactive原理,最后再进行源码的验证。

一、怎么实现变量变化

怎么实现变量变化,相关依赖的结果也跟着变化

Vue3 Reactive响应式原理逻辑详解

 当原本price=5变为price=20total应该变为40,但是实际total并不会改变。 解决办法可以这样,当变量改变了,重新计算一次,那么结果就会改变为最新的结果。

如果需要重新计算,我们需要将total语句存储为一个函数,才能实现依赖的变量改变就进行一次依赖项计算。这里就用effect表示函数名。

来,试一下:

Vue3 Reactive响应式原理逻辑详解

 ??,实现了变量price改变,依赖变量price quantity的变量total也发生改变。

下一步,我们要解决的问题是:应该怎么把effect存储起来,让代码更加有通用性,而不是一直复写effect,分离出其他的功能的函数各司其职,也就是大家常说的解耦

二、怎么实现变量变化

怎么实现变量变化,变量改变后就取出effect执行

用什么存储effect呢?当然是用Set,因为Set会过滤出重复的元素,所以能够保证存储在Set中的函数不是重复的。 这里定义一个存储effect依赖的变量为dep = new Set(),定义track函数表示存储的过程。 定义trigger函数用以取出dep中相关的effect函数执行(这里定义的函数与Vue3源码同名同意义)。

  • effect: 会影响结果的函数(要实现响应式的依赖语句)

  • track:保存所有的effect

  • trigger: 当变量改变重新执行代码

Vue3 Reactive响应式原理逻辑详解

 ??,解耦之后代码结构更清晰了。

下面需要解决的一个问题:一个object通常有多个属性,比如product = { price: 5, quantity: 2 },在保存依赖时只创建了一个dep的集合,应该给pricequantity都创建dep,因为total的最终结果依赖这两个属性,其中任何一个改变都要触发trigger函数。创建了两个dep就需要一个容器将dep存储起来。

三、将多个dep存储在Map中

因为不同的属性名有自己对应的dep,所以我们用Map结构(键值对形式)来保存不同dep

Vue3 Reactive响应式原理逻辑详解

 ??,一个object的多个属性依赖问题解决,更具有通用性了。

下一个问题是:不可能只有一个对象,多个对象又怎么办?let product = { price: 5, quantity: 2 } let user = { firstName: "Joe", lastName: "Smith" },比如两个对象的时候就需要进一步修改上面的代码了。

四、将多个object的depsMap继续存储起来

这里用WeakMap数据结构去存储多个需要响应式的object的depsMapWeakMap的基本使用和Map差不多,只不过WeakMap只接受对象为键值,而depsMap是一个Map结构刚好(必须是)是对象类型。targetMap作为存储多个depsMap的容器名。

Vue3 Reactive响应式原理逻辑详解

??,到这里已经基本实现了通用性的响应式代码了,但是还有最后一个问题就是:我们的代码都需要手动执行(自己添加trigger运行),不能自动运行。怎么让它能够自动检测变量改变,然后自动修改结果呢?

五、核心

通过Reflect和Proxy解决自执行问题

在JavaScript中,自动检测变量不就是get、自动修改变量不就是set吗?在Vue2.x版本中用ES5的Obeject.defineProperty()自带的getter/setter去解决这个问题。ES6中Proxy也能解决这个问题,但是Proxy不兼任IE浏览器,当时大家还讨论过说不知道尤大怎么去考虑这个问题,现在问题的答案就是——不考虑。也就是根本不考虑IE兼不兼容????。

Proxy就是代理的意思,任何对真实数据的操作它都能拦截并且代理操作,也就是说Object上一些能实现的方法,Proxy也能实现。Proxy使用语法是new Proxy(target, hanler)handler是你想实现什么样的代理功能配置。 而Reflect就更神奇了,它的作用是取代Object类上的一些方法让Obeject类更纯粹的代表一个类,不要附加太多方法在上面,比如a in obj表示判断obj中是否有a,在Reflect中用Reflect.has(a)比较语义化的方式就可以代替之前的方法。

正是因为这样,ProxyReflect就对应上了,都有Object上的方法。

稍微封装一下我们的函数,名叫Reactive

Vue3 Reactive响应式原理逻辑详解

 ??,至此,Vue3基本的响应式原理就解析完了。

六、源码解析(TypeScript)

Vue3 Reactive响应式原理逻辑详解

 returncreateReactiveObject函数,所以去看createReactiveObject

Vue3 Reactive响应式原理逻辑详解

 前面的代码都是判断各种情况,我们就看最后几行

const observed = new Proxy(
   target,
   collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers
 )

可以看到ProxyhandlercollectionHandlers或者 baseHandlers,继续选择一个看一看。

在 baseHandlers中可以看到导出了get/set/deleteProperty等属性配置:

Vue3 Reactive响应式原理逻辑详解

我们看一下set

Vue3 Reactive响应式原理逻辑详解

 和我们之前的逻辑差不多,只不过真正实现就很复杂,因为有很多复杂条件需要去处理。

其他的get等方法也一样,做了很多条件判断处理,完善了每一种会出现的情况。

来源:https://juejin.cn/post/6854573217038893070

标签:Vue3,Reactive,响应式,原理
0
投稿

猜你喜欢

  • 修改fckeditor的文件上传功能步骤

    2023-03-19 17:31:28
  • 一张图带我们入门Python基础教程

    2021-07-27 14:19:15
  • javascript自启动函数的问题探讨

    2024-04-30 08:55:57
  • Python实现加密接口测试方法步骤详解

    2022-08-09 20:07:32
  • YOLOv5车牌识别实战教程(七)实时监控与分析

    2021-10-08 17:21:19
  • 在Python中测试访问同一数据的竞争条件的方法

    2023-03-29 15:04:06
  • Python的Flask框架使用Redis做数据缓存的配置方法

    2024-01-21 18:37:47
  • 与MSSQL对比学习MYSQL的心得(五)--运算符

    2024-01-15 17:13:36
  • 将MSSQL Server 导入/导出到远程服务器教程的图文方法分享

    2024-01-13 21:55:42
  • Alexa排名数据xml接口及其参数说明

    2008-11-07 13:03:00
  • 关于Pycharm安装第三方库超时 Read time-out的问题

    2022-03-08 10:12:43
  • python中kmeans聚类实现代码

    2023-09-27 19:49:44
  • pandas对指定列进行填充的方法

    2022-03-15 07:52:51
  • Python列表删除所有出现元素的两种方法

    2023-03-05 23:24:08
  • Oracle SQL性能优化系列学习三

    2010-07-23 13:08:00
  • python将图片转为矢量图的方法步骤

    2022-04-09 10:48:22
  • 使用python opencv对畸变图像进行矫正的实现

    2021-08-18 01:09:44
  • Perl eval函数使用实例

    2022-12-21 05:25:55
  • OpenCV4.1.0+VS2017环境配置的方法步骤

    2022-11-21 18:22:38
  • 基于Python自制一个文件解压缩小工具

    2021-10-15 14:28:00
  • asp之家 网络编程 m.aspxhome.com