学Vue3核心概念与面试官斗智斗勇(一) 收集触发依赖
本文章依据阅读源码的理解进行编写。如果有什么错误的地方,欢迎指正交流学习。
最近也在帮助想入行前端的朋友进行学习,如果有需要交流学习,可以添加微信 gdgzyw。
聊天、学习、打游戏都阔以~
学习源码最快的方式就是理解概念后,自己写一个简版的功能。所以我们得先搭一个环境,这里采用测试驱动的方式进行。
初始化项目
初始化 package.json
和安装依赖
1 | yarn init -y |
添加 scripts
用于启动 jest
package.json
1 | { |
根目录创建 babel.config.js
1 | module.exports = { |
创建 tsconfig.json
文件
1 | { |
至此我们的项目就初始化完成了。如果你需要用 git 来管理,可以自行 git init
。
编写测试用例
创建 src/reactivity/tests/effect.spec.ts
文件
1 | describe('effect', () => { |
创建 scr/reactivity/tests/reactive.spec.ts
1 | describe('reactive', () => { |
现在我们运行 yarn test
测试用例是跑不通的。对应的函数我们还没有创建。下面正式开始我们的编码环节。
编写 reactive 函数
通过上面的测试用例,我们可以知道,我们接收一个对象的值,并且对他进行一个拦截。所以我们可以直接返回一个 proxy 的代理对象。
1 | export function reactive(obj) { |
Reflect.get(target, key) 等同于 target[key]
接着我们为了统一出口可以创建 src/reactivity/index.ts
文件
index.ts
1 | export * from './reactive' |
接着我们去 reactive.spec.ts
中引入我们的函数
1 | import {reactive} from '../index' |
跑一下测试
1 | yarn test reactive |
提示 PASS
至此发现这个的单侧已经跑通。接着我们可以开始写另一个单测。
编写 effect 函数
一样的,我们观察一下测试用例的参数。
可以发现他接受一个回调,所以我们参数是一个回调函数。
接着我们思考一下如何将我们上一个 reactive 的函数与这个回调函数产生关联。
定义 tagetMap 变量,用于对象的分组。
定义 depsMap 变量,用于对象中每个 key 的依赖分组。
通过 reactive 定义对象,在 get 的时候,我们在 targetMap
中将对象添加到 Map 中作为分类。接着创建 Set 用 key 作为分类保存到 Set 中。
回顾我们的单侧流程,我们先定义了个 reactive 对象。
接着我们在 effect 函数中执行了回调函数,回调函数中我们会读取到 reactive 的值,从而触发了 get 操作。所以我们需要在 get 操作中进行依赖收集。
定义一个 ReactiveEffect 类,收集我们的回调函数
src/reactivity/effect.ts
1 | let activeEffect |
在初始化的时候,我们保存回调函数到 _fn 中,在我们执行 run 方法的时候。会触发我们的回调函数。
定义一个 track 的函数,完成收集依赖这个操作
src/reactivity/effect.ts
1 | const targetMap = new Map() |
如果此时我们需要设置 reactive 的值,我们会触发 set 操作。所以触发依赖的操作需要在 set 中进行。
定义 trigger 函数,触发所有依赖
1 | export function trigger(target, key) { |
回到 reactive 文件,将 track 和 trigger 写到对应的操作中。
src/reactivity/index.ts
1 | // ... |
src/reactivity/reactive.ts
1 | import {target, trigger} from './index' |
回到我们的单侧,将这几个库引入
src/reactivtiy/tests/effect.spec.ts
1 | import {effect,reactive} from '../index' |
至此我们收集依赖和触发依赖的核心逻辑已经实现。我们现在可以跑 yarn test
进行检验。
结语
这篇文章是这个系列的开始,后续我会继续分享相关内容。慢慢完善我们对 vue3 的理解。
欢迎关注我,与我深入♂沟通。