专栏前言
在上一节,我们完成了vue3的ref核心源码解读,其实基础类型的ref的核心逻辑还是非常简单的,所以在我们的简易版源码环节,我们直接切入基础类型,复杂类型仅做支持,不做讲解。
注:单基础类型场景的ref源码,几乎可以说是整个vue3源码中最简单的一部分,所以这一节的学习难度是最小的
mini版vue3仓库地址,还请大家不要吝啬star,下次不迷路~
仅保留最核心逻辑,极大减低阅读难度,80行代码实现vue3 ref,让我们直接进入源码实现环节!
逻辑图(基础类型)
完整版ref逻辑图,请看 Vue3硬核源码解析系列(5) ref源码解析
具体逻辑
如同逻辑图所示,我们简易版源码的具体实现也从 初始化 依赖收集 依赖触发三个角度来进行实现
初始化
ref的初始化非常简单,逻辑流程如下
- 判断传入对象是否已经是ref,如果是,这直接返回,如果不是,则继续运行代码
- ref的本质就是一个Class RefImpl
- 初始化RefImpl的时候,将ref的参数保存到
_value
,同时将参数的原始值保存到_rawValue
- 通过get value,实现ref.value的访问
- 使用set value,实现ref.value = xx的更新逻辑
确定实现逻辑的同时,我们也仿照vue3的源码结构开始输出吧~
1 | /** |
依赖收集
ref = Class RefImpl
经过我们上一章的ref源码分析我们可以了解到,ref的依赖收集,并不是依赖WeakMap进行完成,而是其自行完成依赖收集,收集在自身class的dep中,逻辑大概是这样的
- 每次触发ref的get的时候,都会执行一次trackRefValue(trackRefValue的作用是完成依赖收集)
- 每次执行effect的时候,都会将effect本身保存到变量activeEffect中(具体请看Vue3硬核源码解析系列(3) reactive + effect源码解析)
- 如果RefImpl的dep不存在,则说明是第一次进行依赖收集,将通过createDep将RefImpl.dep赋值为Set
- 将activeEffect,也就是当前正在运行的effect,push到RefImpl的dep中,ref完成依赖收集
明确了逻辑之后,我们依旧结合vue3的源码结构,来完成ref依赖收集的代码输出。
1 | get value() { |
依赖触发
若干时间后,ref的value被更新,触发RefImpl的set value,在更新value的同时,也会执行其内部的triggerRefValue,开始依赖触发逻辑
- 获取到当前ref,也就是class RefImpl本身的dep
- 循环dep中存储的所有effect,并执行其fn,完成依赖触发。
1 | /** |
到此为止,我们的ref就具备响应式的能力了,是不是很简单~
小结
这时候肯定有同学要说了,你这ref不保熟啊,仅支持基础类型,不支持复杂类型啊,这不是阉割版ref吗?
这里必须澄清一下,虽然简易版ref 100行代码不到,但是他是支持复杂类型的响应式的,因为复杂类型的响应式是依赖reactive进行完成的,不过reactive的源码解读,并不是本文的重点,所以,这里就跳过了,有兴趣的同学,请看这里Vue3硬核源码解析系列(3) reactive + effect源码解析,了解reactive的响应式实现,再看Vue3硬核源码解析系列(5)ref源码解析,了解复杂类型场景下的源码执行逻辑吧。
最后,建议大家clone源码到本地实际运行一下,静下心来一步一步调试,将简易版逻辑弄明白,有兴趣的可以在看看正式的vue3源码,在简历上留下浓墨重彩的一笔~