实现vue3响应式系统核心-shallowReactive

shallowReactive

简介

今天来实现一下 shallowReactive 这个 API。

reactive函数是一个深响应,当你取出的值为对象类型,需要再次调用 reactive进行响应式处理。很明显我们目前的代码是一个浅响应,即 只代理了对象的第一层,也就是 shallowReactive

代码地址: https://github.com/SuYxh/share-vue3

代码并没有按照源码的方式去进行组织,目的是学习、实现 vue3 响应式系统的核心,用最少的代码去实现最核心的能力,减少我们的学习负担,并且所有的流程都会有配套的图片,图文 + 代码,让我们学习更加轻松、快乐。

每一个功能都会提交一个 commit ,大家可以切换查看,也顺变练习练习 git 的使用。

单元测试

it('深响应 reactive', () => {const mockFn = vi.fn();const obj = reactive({ foo: { bar: 1 } })effect(function effectFn() {console.log(obj.foo.bar);})expect(mockFn).toHaveBeenCalledTimes(1);obj.foo.bar = 2expect(mockFn).toHaveBeenCalledTimes(2);
})it('浅响应 shallowReactive', () => {const mockFn = vi.fn();const obj = shallowReactive({ foo: { bar: 1 } })effect(function effectFn() {console.log(obj.foo.bar);})expect(mockFn).toHaveBeenCalledTimes(1);obj.foo.bar = 2expect(mockFn).toHaveBeenCalledTimes(1);
})

代码实现

reactive函数的get中,增加如下判断:

if (typeof res === 'object' && res !== null) {return reactive(res)
}

新增一个shallowReactive 函数并导出, 和之前的 reactive函数一样。

运行单测

深响应 reactive:

image-20240122004441759

浅响应 shallowReactive:

image-20240122004510851

都没有问题!

重构

我们看到 shallowReactivereactive有极大的相似,需进行代码抽离:

export function createReactive(target, isShallow = false) {return new Proxy(target, {// 拦截读取操作get(target, key, receiver) {// 代理对象可以通过 raw 属性访问原始数据if (key === symbolRaw) {return target;}const res = Reflect.get(target, key, receiver);//  如果是浅响应,则直接返回原始值if (isShallow) {return res;}if (typeof res === "object" && res !== null) {return reactive(res);}// 依赖收集track(target, key);return res;},// 拦截设置操作set(target, key, newVal, receiver) {// 先获取旧值const oldVal = target[key];// 如果属性不存在,则说明是在添加新属性,否则是设置已有属性const type = Object.prototype.hasOwnProperty.call(target, key)? TriggerType.SET: TriggerType.ADD;// 设置属性值const res = Reflect.set(target, key, newVal, receiver);// target === receiver.raw 说明 receiver 就是 target 的代理对象if (target === receiver[symbolRaw]) {// 较新值与旧值,只有当它们不全等,并且不都是 NaN 的时候才触发响应if (oldVal !== newVal && (oldVal === oldVal || newVal === newVal)) {trigger(target, key, type);}}return res;},// 拦截 in 操作符has(target, key) {track(target, key);return Reflect.has(target, key);},// 拦截 for in 循环ownKeys(target) {track(target, ITERATE_KEY);return Reflect.ownKeys(target);},// 拦截删除deleteProperty(target, key) {// 检查被操作的属性是否是对象自己的属性const hadKey = Object.prototype.hasOwnProperty.call(target, key);// 使用 Reflect.deleteProperty 完成属性的删除const res = Reflect.deleteProperty(target, key);if (res && hadKey) {// 只有当被删除的属性是对象自己的属性并且成功删除时,才触发更新trigger(target, key, TriggerType.DEL);}return res;},});
}// 对原始数据的代理
export function reactive(target) {return createReactive(target);
}export function shallowReactive(target) {return createReactive(target, true);
}

运行测试

pnpm test

image-20240122004859928

重构后的代码也没有问题!

引导扫码关注

一个前端小学生的学习之路,如果你喜欢前端,我们可以一起进行学习、交流、共建。可以添加好友,结伴学习,成长的路上不孤单!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/442255.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【java核心-IoC(控制反转)和DI(依赖注入)及AOP(面向切面编程)】

java核心-IoC(控制反转)和DI(依赖注入)及AOP(面向切面编程) 控制反转(IoC)依赖注入(DI)面向切面编程(AOPAOP的应用场景包括但不限于:以…

安装和启动berTopic,hdbscan和importlib.metadata

1. 安装问题:hdbsacn 安装berTopic的时候,包 hdbsacn一直安装失败,报出以下错误: 尝试了很多办法:① 下载hdbscan的tar.gz文件安装,安装失败;② 安装*.whl文件,安装成功&#xff…

【C++初阶】C++入门(2)

🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 文章目录 一、函数重载1.1 函数重载的概念1.2 函数重载的种类1.3 C支持函数重载的原理 二…

海外短剧系统国际短剧源码h5多语言版app挂载tiktok油管ins

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目 前言 一、海外短剧系统是什么? 二、海外短剧系统功能与运营方式介绍 1.系统功能 2.短剧APP运营方式 总结 前言 本文简单介绍海外短剧系统的功能&#xff…

Flutter的安装与环境配置

一、下载安装Futter: 1、Flutter中文文档: 安装和环境配置 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 2、下载 Futter SDK: Flutter中文文档 里面有,下载完成之后找个文件夹解压出来,最好不要将 Flu…

asp.net core监听本地ip地址

开发asp.net core的时候遇到一个问题我想提供访问供其他同事测试,但是默认都是localhost或者127.0.0.1。我想换成我的Ip地址访问但是不行,百度搜索需要更换监听的地址即修改launchSettings.json,修改为0.0.0.0:5248,这样不管local…

Enlight官方第三届“金融帝国杯”玩家游戏视频邀请赛《获奖者名单公布》

Enlight官方第三届“金融帝国杯”玩家游戏视频邀请赛 《获奖者名单公布》 ————————————— Ⅰ〖公布单位〗 金融之路CapLab官方中文社群竞赛委员会 ————————————— Ⅱ〖公布时间〗 2024年01月31日 ————————————— Ⅲ〖获奖结果〗 一等奖1名…

gdp调试—Linux

目录 介绍 使用 介绍 代码分为debug模式和release模式 如果一份代码要被调试,这份代码必须是debug Linux下编译代码默认是是release模式 如果你想代码是debug模式 必须加上 - g 小提: vim默认:命令模式 gcc默认:releas…

比Filebeat更强大的日志收集工具-Fluent bit的http插件实战

文章目录 1.前言2. fluent bit http插件配置以及参数详解3. Http 接口服务3.1 开发Http 接口服务3.2 重启fluent bit向http web服务发送数据 1.前言 Fluent Bit 的 HTTP 插件提供了一种灵活而通用的机制,可用于将日志数据 从各种环境中传输到指定的远程服务器&#…

【JVM】类加载流程

目录 1.加载 2.链接 (1)校验 (2)准备 (3)解析 3.初始化 4.使用 5.卸载 1.加载 加载阶段,简言之,查找并加载类的二进制数据,生成 Class 的实例 在加载类时&#x…

5. Threejs案例-制作半色调和旋转效果

5. Threejs案例-制作半色调和旋转效果 实现效果 代码 <!DOCTYPE html> <html lang"en"> <head><title></title><meta charset"UTF-8"><script src"ThreeJS/three.js"></script><script sr…

X-tile的使用选择最适cut-off值

数据准备&#xff1a; 将此数据存成txt&#xff08;文本文件&#xff0c;制表符分隔&#xff09;。 打开x-tile并点击分析&#xff1a; 然后File-open-选择数据导入。 Censor对应OS即生存状态&#xff0c;Survivaltime对应OS.time生存时间&#xff0c;marker1就是要研究的变量…