回顾下前几章的内容,在前几章中主要讲述了以下内容。
- 新构建工具
vite
的原理和从零开始实现 vue3
使用新姿势- 新api:
reactive
使用和源码解析 - 追踪收集
track
实现和源码解析 - 追踪触发器
trigger
实现和源码解析 - 响应式核心
effect
与track、trigger
工作原理和源码解析
好的,这章的目标:从零开始完成一个 Vue3 !
必须要知道的前置知识 effect
与 track、trigger
工作原理,具体详情请看公众号 -> 前端进阶课
,一个有温度且没有广告的前端技术公众号。
在这里还是简单解析下这3个函数的作用吧
- track: 收集依赖,存入
targetMap
- trigger:触发依赖,使用
targetMap
- effect:副作用处理
本章源码请看 uuz 急需 star 维持生计。
手摸手实现 Vue3
首先。我们2个全局变量,用来存放和定位追踪的依赖,也就是给 track
和 trigger
使用的仓库。
let targetMap = new WeakMap();
let activeEffect;
所以第一个需要设计的方法就是 track
,还记得该track
在vue3是如何调用的吗?
track(obj, 'get', 'x');
track
会去找 obj.x
是否被追踪,如果没找到就将obj.x放入targetMap
(完成追踪任务),将 obj.x
作为 map 的 key 将 activeEffect 作为 map 的 value。
抛开取值异常处理之类的,track
只做了一件事,将activeEffect
塞入targetMap
;
然后就是写一个 trigger
,还记得trigger
在vue是如何调用的吗?
trigger(obj, 'set', 'x')
trigger
只会去 targetMap
中寻找obj.x
的追踪任务,如果找到了就去重,然后执行任务。
也就是说:抛开取值异常相关,trigger
也只做了一件事:从 targetMap
取值然后调用该函数值。
最后就是 effect
,还记得该打工仔的api在vue3中是如何调用的吗?
effect
接收一个回调函数,然后会被送给 track
。所以我们可以这么完成 effect
- 定义一个内部函数
_effect
,并执行。 - 返回一个闭包
而内部 _effect
也做了两件事
- 将自身赋值给
activeEffect
- 执行
effect
回调函数
优秀的代码呼之欲出。
所有的前置项都完成了,现在开始完成一个 reactive
,也就是对象式响应式的api。还记得vue3中如何使用 reactive
吗?
通过上面的的优秀代码,很轻易的实现了vue3的响应式操作。通过回顾前几章的内容,我们知道 reactive
是通过 Proxy 代理数据实现的。
这样我们就可以通过 Proxy
来调用 track
和 trigger
,劫持 getter
和 setter
完成响应式设计
好了。一切就绪,那么我们挂载下我们的 fake vue3
吧
用 self-vue3 写一个 demo
测试一下。参照 vue3 的写法。定义个 setup
和 re
nder
。
执行一下,果然是优秀的代码。响应式正常执行,每次 setInterval
执行后,页面都重写刷新了 count.num
的数据。
源码请看 uuz,ps:7月23日该源码已经支持 jsx 了。
以上通过 50+
行代码,轻轻松松的实现了 vue3
的响应式。但这就结束了吗?
还有以下问题
Proxy
一定需要传入对象render
函数 和h
函数并正确(Vue3的h函数现在是2个不是以前的createElement
了)- 虚拟 dom 的递归
- 别再说了
- -!
,我不听。
ref
使用 reactive 会有一个缺点,那就是,Proxy 只能代理对象,但不能代理基础类型。
如果你调用这段代码 new Proxy(0, {})
,浏览器会反馈你 Uncaught TypeError: Cannot create proxy with a non-object as target or handler
所以,对于基础类型的代理。我们需要一个新的方式,而在 vue3
中,对于基础类型的新 api 是 ref
总结:
- reactive 的核心是
track
+trigger
+Proxy
- ref 是通过对象自有的
getter
和setter
配合track
+trigger
实现的 - computed 其实是一个在
effect
基础上的改进
下章内容:vue3
该怎么结合 jsx
?