前言
想必 vue3
作为前端应该没有不知道的吧,采用了 MVVM
的数据视图链接方式,数据发生改变,视图可以跟随变化,今天我们来实现这个效果
先看效果图,一秒以后 视图自动从 zs
到 lisi
代码
现在就来实现 effect
函数 和 reactive
(由于是 简化版,了解思想即可)
effect 的细节可以看这里👉 #Vue 中的响应性是如何工作的
分析
reactive
首先看 reactive
函数,接收一个对象,返回了一个响应式对象 r
, 而且这个r
有着和传入对象一样的结构,与此同时我们需要对传入的这个对象进行监听,如果有修改值的行为,就要执行对应的 effect
函数
这就让我们想到 Proxy
我们可以利用proxy
对传入的对象进行监听
关于
proxy
的细节可以看这里 👉 MDN-Proxy
- 如果在
effect
中有用到reactive
的key
值时,我们需要收集那些使用了reactive
的key
值的 effect 函数, 以便后续数据更改时触发 - 如果传入对象的有变化时,刚好
effect
中使用到了这个key
值,就要重新触发对应的effect
effect
一个简单的高阶函数,会默认执行一次
如果传入的函数中有引用的 reactive
变量, 并且 对应的 key
值 的 value
发生了变化,那么就要重新执行
代码
reactive
很简单写下如下代码
如果不懂
Reflect
,可以戳这里👉MDN-Reflect
🔥🔥🔥🔥 track 收集依赖
首先我们要明确一点,我们在使用 vue 的过程中,一般不太可能只定义一个 reactive
,一定有很多个
同时呢,effect
可能引用了不同的 reactive
中不同的 key
值
也就是 effect
和 reactive
是 多对多的关系
如下图所示
所以在收集依赖的时候,就要设计一种数据结构满足多个对象,对象中的多个key 值,收集不同依赖的情况
我们想到了这种结构,用图片表示是这种 👇
用代码表示是这种 👇
ok,如果明确了思路,那么接下来的编码环节就是水到渠成了
🔥🔥 trigger 触发依赖
那么trigger
就很简单了,找到对应的 对象
,然后找到对象的这个 key
,再通过这个 key
值找到对应的 effect
,让 effect
运行起来就可以了
ok,如果你理解了上面最难的收集依赖的部分,那么 effect
就简单的多了
effect
effect 接收一个函数,这个函数会默认调用一次
如果这个函数中有引用了reactive
的key
值,那么就会触发收集依赖的操作
,当前effect
要被 对应的key
收集
如果后面key有变化,则会触发 reactive
的 触发依赖的操作
,那么 effect
就要重新执行
代码如下图所示
有小伙伴就要好奇了,上面的代码我都理解,这个activeEffect
和 deps
是什么意思呢
这个就是effect
收集的reactive
对应的key
值依赖
-
由于第一次
reactive
会默认执行,把fn
传入ReactiveEffect
类中,并保存 -
执行
ReactiveEffect
实例上的run
方法,执行run
方法的时候,把全局变量 activeEffect
设置为this
-
接下来执行
fn
,这个时候触发了Proxy
中的get
操作,那么就要执行track
操作了 -
在
track
中,不仅dep
收集全局变量 activeEffect
(即当前 effect 中的 ReactiveEffect 实例),同时全局变量 activeEffect
也收集了对象的dep
总而言之,谁收集了我,我就要反过来收集它,是一个相互收集的过程
有兴趣的小伙伴可以看下这个👇
总结
依赖收集在vue
中还是挺重要的,它是 vue
的基础,像ref
,computed
,watch
,...
都是基于这个上面的这个依赖收集,还有onMounted
等一众生命周期钩子也用到了这个依赖收集
最后一句话:源码是用来借鉴思想的,不必拘泥于形式,虽然上面我写的很简单,但是核心就是这么多。
如果有不同意见,可以在评论区讨论,一起进步呀