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

news2024/11/28 0:41:15

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 = 2
  expect(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 = 2
  expect(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.coloradmin.cn/o/1425641.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

以 AI 升级自我 | Kyligence 荣获多个奖项及榜单认可

回顾 2023 年的企业开年信,Kyligence 联合创始人兼 CEO 韩卿借用了历史上一句经典口号“时间就是金钱,效率就是生命”,鼓励团队顺势而为,抓住时代的机会,快速发展,快速成长。 Kyligence 一直都在践行“Ret…

【系统设计】12306架构设计难点(下)

欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送! 在我后台回复 「资料」 可领取编程高频电子书! 在我后台回复「面试」可领取硬核面试笔记! 文章导读地址…

Linux第38步_编译“正点原子移植好的uboot”

uboot的全称是Universal Boot Loader,uboot是一个遵循GPL协议的开源软件,uboot是一个裸机代码,可以看作是一个裸机综合例程。现在的 uboot 已经支持液晶屏、网络、USB等高级功能。 uboot官方的uboot源码是给所有的半导体厂商准备的。ST公司会…

c++ 字符串切分split

c 字符串切分split 的举例实现 一共给出了四种方式 1、 strtok 2、 stringstream 3、 字符串查找 4、 基于封装的方式&#xff0c;提供了 c11 foreach 接口 代码 vector<string> split(string s) {vector<string> res;const char *p strtok((char *) s.c_str(),…

【LVGL源码移植】

LVGL源码移植 ■ LVGL源码移植一&#xff1a;下载LVGL源码二&#xff1a;修改LVGL文件夹1: 将这5个文件&#xff0c;复制到一个新的文件夹2: 简化文件&#xff0c;减少内存消耗&#xff08;去除不必要的文件&#xff09;3: 为了规范化&#xff0c;我们将下列文件进行重命名 三&…

强化学习 - Monte Carlo Tree Search (MCTS)

什么是机器学习 强化学习中的Monte Carlo Tree Search (MCTS) 是一种用于决策制定和搜索的算法&#xff0c;特别在不确定环境下表现出色。 1. 强化学习背景 在强化学习中&#xff0c;一个智能体通过与环境的交互学习&#xff0c;以便在某个任务上获得最大的奖励。MCTS是一种…

Kotlin 协程:深入理解 ‘lifecycleScope‘

Kotlin 协程&#xff1a;深入理解 ‘lifecycleScope’ Kotlin 协程是一种强大的异步编程工具&#xff0c;它提供了一种简洁、易读的方式来处理并发和异步操作。在 Kotlin 协程库中&#xff0c;lifecycleScope 是一个关键的概念&#xff0c;它允许我们将协程的生命周期绑定到 An…

LeetCode 828. 统计子串中的唯一字符

一开始想的是两次前缀和&#xff0c;发现自己蠢了 看了灵神的题解&#xff0c;类似于DP的思想 我们维护以每个字符串结尾的子字符串对答案的贡献&#xff0c;s[i]的贡献是多少&#xff1f;首先我们知道他需要自己单独一个串或者接在以s[i-1]结尾的那些字符串的后面&#xff0c…

从法律风险的角度看待项目验收前自测的必要性

大家好&#xff0c;我是不会魔法的兔子&#xff0c; 一枚从事企业合同纠纷预防与解决的执业律师&#xff0c;从法律的角度分享关于项目管理中的问题及预防&#xff0c;让项目管理者能够提早发现与解决项目执行过程中的风险&#xff0c;同时欢迎大家一起交流&#xff0c;微信搜…

做外贸发货时发现货物有问题要怎么办

一个客户向一个伙伴订购了一批衣服&#xff0c;在准备装货的时候&#xff0c;小伙伴到工厂检查货物&#xff0c;发现衣服非常的潮湿&#xff0c;于是小伙伴担心货物万一经过长期的海运&#xff0c;到达客户那边发霉了怎么办呢&#xff1f; 但是工厂这边已经打好包装&#xff0c…

MySQL备份和恢复(二)mysqldump

注意&#xff1a;mysqldump是完全备份 一、mysqldump备份命令 1、 备份数据库 含创建库语句 &#xff08;1&#xff09;备份指定数据库 完全备份一个或多个完整的库&#xff0c; mysqldump -uroot -p[密码] --databases 库名1 [库名2].. >/备份路径/备份文件名.sql#导出…

CS144--Chapter0--wsl2+docker环境搭建

我的笔记本配置 荣耀magicbook16&#xff0c;容量是500G&#xff0c;芯片是R7-5800 由于笔记本容量较小&#xff0c;因此考虑这个方案&#xff0c;对于台式机用户&#xff0c;建议可以直接用虚拟机或者双系统。 前言 斯坦福官网给出的方法是用他们的镜像&#xff08;基于Ubu…

【Vue】2-8、Axios 网络请求

cdn&#xff1a;<script src"https://unpkg.com/axios/dist/axios.min.js"></script> 注&#xff1a;使用 CDN 链接就可以不需要去下载对应的 js 文件到本地&#xff0c;只需要联网即可使用&#xff0c;可以减少项目的体积 <!DOCTYPE html> <…

minio文件跨域问题

问题&#xff1a; 最近前端获取音频的波形报了个错&#xff1a; Access to audio at http://xxx/03.wav from origin http://zzz has been blocked by CORS policy: The Access-Control-Allow-Origin header contains multiple values zzz, *, but only one is allowed. 很奇怪…

FullStack之Django(2)模型和后台

FullStack之Django(2)模型和后台 author: Once Day date:2022年2月13日/2024年1月31日 漫漫长路&#xff0c;才刚刚开始… 全系列文档请查看专栏: FullStack开发_Once_day的博客-CSDN博客Django开发_Once_day的博客-CSDN博客 参考文档: 编写你的第一个 Django 应用&#…

归并排序----C语言数据结构

目录 引言 1.归并排序的实现----c2.归并排序的复杂度分析时间复杂度空间复杂度 引言 归并排序&#xff08;Merge Sort) 是一种基于分治法的排序算法&#xff0c;它的基本思想是将原始数组划分成较小的数组&#xff0c;然后递归地对这些小数组进行排序&#xff0c;最后将排好序…

实战项目(二)汽车保养管家系统

一、实现技术 前端技术&#xff1a;html、javascript(jquery、ajax、json)、css、layui 后端技术&#xff1a;java、mysql、servlet 开发工具&#xff1a;eclipse、vscode 二、项目描述 基于web的汽车保养管家系统的设计与实现 一、功能需求 1&#xff0e;用户功能 1.1…

Flink 1.18.1 部署与配置[CentOS7]

静态IP设置 # 修改网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33# 修改文件内容 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOstatic IPADDR192.168.18.128 NETMASK255.255.255.0 GATEWAY192.168.18.2 DEFROUTEyes IPV4_FAILURE_FATALno IPV6INIT…

nodejs基于vue奖学金助学金申请系统08ktb

高校奖助学金系统的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品&#xff0c;体验高科技时代带给人们的方便&#xff0c;同时也能让用户体会到与以往常规产品不同的体验风格。 与安卓&#xff0c;iOS相比较起来&#xff0c;…

【京东云新品发布月刊】2024年1月产品动态来啦

1&#xff09;【莫奈可视化平台】新品上线 京东莫奈可视化平台通过自由拖拽、图形化编辑、所见即所得的方式&#xff0c;快速实现极致酷炫、直观清晰的视觉场景&#xff0c;将海量繁杂数据背后所蕴含的价值更直观、深层、全面的展现出来&#xff0c;辅助决策者合理决策。 2&a…