当前位置: 首页 > news >正文

实现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 = 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

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

引导扫码关注

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

相关文章:

  • 【国产MCU】-CH32V307-通用DMA控制器及使用
  • 云微呼AI外呼:数字时代营销的智能引擎
  • 【30秒看懂大数据】变量
  • 8、应急响应-战前溯源反制主机蜜罐系统HFishHIDSElkeidWazuh
  • 在QT Creator中打开一个包含CMakeLists.txt的项目时,只打开CMakeLists.txt文件而没有自动打开其他文件
  • mongodb config
  • linux 组建和卸载raid1、raid0详细操作
  • PYTHON蓝桥杯——每日一练(简单题)
  • sql注入之union联合注入
  • 留学生怎么合理使用ChatGPT ?还有哪些同类工具可以使用?
  • 算法练习02——双指针
  • react useCallback(记忆函数)用法
  • 互联网加竞赛 基于深度学习的动物识别 - 卷积神经网络 机器视觉 图像识别
  • 【SVN在Linux下的常用指令】
  • LeetCode 每日一题Day 54 - 61
  • C语言实现12种排序算法
  • 记录element-plus树型表格的bug
  • MySQL常用命令集
  • linux ln命令-linux软链接、硬链接-linux软、硬链接的区别(一):硬链接
  • 【ArcGIS微课1000例】0096:dem三维块状表达(层次地形模型)
  • 红场阅兵即将开始!中国人民解放军仪仗队亮相
  • 屈晓华履新四川省社科联党组书记,此前担任省国动办主任
  • 太空摄影的发展
  • 人民日报评论:莫让“胖东来们”陷入“棒杀”“捧杀”泥潭
  • 无人机穿越大理崇圣寺千年古塔时“炸机”,当地:肇事者已找到,将被追责
  • 两千万粉丝网红“大LOGO”带货茶叶被指虚假宣传,涉事茶企被立案调查