[ 极简实现 🚀 ] - vue3 依赖收集

591 阅读4分钟

前言

想必 vue3 作为前端应该没有不知道的吧,采用了 MVVM 的数据视图链接方式,数据发生改变,视图可以跟随变化,今天我们来实现这个效果

先看效果图,一秒以后 视图自动从 zslisi

动画.gif

代码

code.png

现在就来实现 effect 函数 和 reactive (由于是 简化版,了解思想即可)

effect 的细节可以看这里👉 #Vue 中的响应性是如何工作的

分析

reactive

首先看 reactive 函数,接收一个对象,返回了一个响应式对象 r, 而且这个r 有着和传入对象一样的结构,与此同时我们需要对传入的这个对象进行监听,如果有修改值的行为,就要执行对应的 effect 函数 这就让我们想到 Proxy

我们可以利用proxy对传入的对象进行监听

关于 proxy 的细节可以看这里 👉 MDN-Proxy

  • 如果在 effect 中有用到 reactivekey 值时,我们需要收集那些使用了 reactivekey 值的 effect 函数, 以便后续数据更改时触发
  • 如果传入对象的有变化时,刚好 effect 中使用到了这个 key 值,就要重新触发对应的 effect

effect

一个简单的高阶函数,会默认执行一次
如果传入的函数中有引用的 reactive 变量, 并且 对应的 key值 的 value 发生了变化,那么就要重新执行

代码

reactive

很简单写下如下代码

code.png

如果不懂 Reflect,可以戳这里👉MDN-Reflect

🔥🔥🔥🔥 track 收集依赖

首先我们要明确一点,我们在使用 vue 的过程中,一般不太可能只定义一个 reactive,一定有很多个
同时呢,effect 可能引用了不同的 reactive 中不同的 key

也就是 effectreactive 是 多对多的关系

如下图所示 image.png

所以在收集依赖的时候,就要设计一种数据结构满足多个对象,对象中的多个key 值,收集不同依赖的情况

我们想到了这种结构,用图片表示是这种 👇

image.png 用代码表示是这种 👇

code.png

ok,如果明确了思路,那么接下来的编码环节就是水到渠成了

code.png

🔥🔥 trigger 触发依赖

那么trigger 就很简单了,找到对应的 对象,然后找到对象的这个 key,再通过这个 key 值找到对应的 effect,让 effect 运行起来就可以了

code.png

ok,如果你理解了上面最难的收集依赖的部分,那么 effect 就简单的多了

effect

effect 接收一个函数,这个函数会默认调用一次
如果这个函数中有引用了reactivekey值,那么就会触发收集依赖的操作当前effect 要被 对应的key 收集
如果后面key有变化,则会触发 reactive触发依赖的操作,那么 effect 就要重新执行

代码如下图所示

code.png

有小伙伴就要好奇了,上面的代码我都理解,这个activeEffectdeps 是什么意思呢 这个就是effect收集的reactive对应的key值依赖

  1. 由于第一次reactive会默认执行,把 fn传入 ReactiveEffect类中,并保存

  2. 执行ReactiveEffect实例上的run方法,执行run方法的时候,把全局变量 activeEffect设置为 this

  3. 接下来执行fn,这个时候触发了 Proxy 中的 get 操作,那么就要执行 track操作了

  4. track中,不仅 dep 收集全局变量 activeEffect(即当前 effect 中的 ReactiveEffect 实例),同时 全局变量 activeEffect 也收集了对象的dep

总而言之,谁收集了我,我就要反过来收集它,是一个相互收集的过程

image.png

有兴趣的小伙伴可以看下这个👇

总结

依赖收集在vue 中还是挺重要的,它是 vue 的基础,像ref,computed,watch,...都是基于这个上面的这个依赖收集,还有onMounted等一众生命周期钩子也用到了这个依赖收集
最后一句话:源码是用来借鉴思想的,不必拘泥于形式,虽然上面我写的很简单,但是核心就是这么多。
如果有不同意见,可以在评论区讨论,一起进步呀