实现手动执行的响应式
上篇文章,我们粗略的梳理了一遍响应式的概念,看过上篇文章的同学应该明白了什么是响应式,以及我们为什么需要响应式。如果不明白的同学,建议从第一篇文章如何理解响应式原理 (opens new window)开始食用,味道更佳。其实上一篇文章我们基本已经实现了Vue3中响应式原理的雏形,但是还有很多地方不完善,功能也没有完全实现。从这篇文章开始,我们将按照Vue3中响应式实现的思路一步一步手动实现一遍响应式。
首先我们先实现最简单的例子,我们通过手动调用函数的方式实现响应式。有这样一个例子:
let total = 0
let price = 10
let quantity = 2
// 这个就是副作用函数
let effect = () => {
total = quantity * price
}
// 修改价格 price
price = 20
// 期待总价更新
console.log(total) // 40
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
当我们修改价格price
的时候,我们希望total
的值也能得到更新,也就是effect
需要执行。根据上文提到的思想,我们首先需要收集依赖,那这里大家可以想想我们收集的依赖用什么数据结构保存最好呢?还是用上文提到的数组吗?其实也不是不可以,但是我们考虑这样的场景:依赖被重复收集,比如:
const effects = []
let effect = () => {
// ...
}
// 第一次收集 正常
effects.push(effect)
// 第二次收集 重复依赖 没有必要
effects.push(effect)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
所以说使用数组我们还需要手动去重,那么有更好的集合可以做到自动去重吗?这里可能大家都想到了,那就是使用Set
。同时我们定义track
函数用来收集依赖,如下:
// 保存effect
let dep = new Set()
// 收集依赖函数
function track() {
dep.add(effect)
}
1
2
3
4
5
6
7
2
3
4
5
6
7
紧接着,依赖收集好之后,我们还需要一个trigger
函数去触发。定义如下:
// 触发依赖函数
function trigger() {
dep.forEach(effect => effect())
}
1
2
3
4
2
3
4
完整代码如下:
// 保存effect
let dep = new Set()
// 收集依赖函数
function track() {
console.log('执行了吗')
dep.add(effect)
}
// 触发依赖函数
function trigger() {
dep.forEach(effect => effect())
}
// 测试例子
let total = 0
let price = 10
let quantity = 2
// 这个就是副作用函数
let effect = () => {
total = quantity * price
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
我们测试一下:
price = 20
track()
trigger()
console.log(total) // 40
1
2
3
4
2
3
4
这样我们就实现了手动收集依赖和手动触发依赖的功能。但是,读过第一篇文章的同学肯定知道,我们期望的场景是我们只需要定义需要响应式的数据,而依赖收集和依赖触发是自动执行的,这样才是完美的。这正是我们下一篇文章需要实现的。
编辑 (opens new window)
上次更新: 2021/10/30, 16:48:40