实现Vue3中isReactive和isReadonly

本文是 Vue3 源码实战专栏的第 5 篇。

往期文章

搭建项目环境,集成ts和jest

reactive和effect,依赖收集触发依赖

完善effect功能

实现readonly,重构是一步步进行的

实现Vue3中isReactive和isReadonly

isReactive

isReactive()检查一个对象是否是由 reactive()shallowReactive() 创建的代理。

使用

<script setup>
import { isReactive, reactive } from "vue";
const user1 = reactive({ name: "wendZzoo" });
const user2 = { name: "wendZzoo" };
</script>

<template>
{{ isReactive(user1) }}
{{ isReactive(user2) }}
</template>

页面上展示true false

单测

在原本的reactive单元测试上添加isReactive测试断言。

import { isReacive, reactive } from "../reactive";

describe("reactive"() => {
  it("happy path"() => {
    let original = { foo: 1 };
    let data = reactive(original);
    expect(data).not.toBe(original);
    expect(data.foo).toBe(1);
    
    // isReactive
    expect(isReacive(data)).toBe(true);
    expect(isReacive(original)).toBe(false);
  });
});

实现

判断一个对象是否是reactive创建的代理,那在访问该对象时会触发其get操作,可以定义当前的对象上是否存在一个key来判断。

reactive.ts文件中导出isReactive方法,

export function isReacive(value{
  return !!value['is_reactive'];
}

改造get函数,

function createGetter(isReadonly = false{
  return function get(target, key{
    let res = Reflect.get(target, key);

    if (key === "is_reactive") {
      return !isReadonly;
    }

    if (!isReadonly) {
      track(target, key);
    }
    return res;
  };
}

执行单测yarn test reactive验证isReactive方法是否正确。

优化

定义一个枚举类型来管理is_reactive这样的变量。

export const enum ReactiveFlags {
  IS_REACTIVE = "__v_isReactive"
}
export function isReacive(value{
  return !!value[ReactiveFlags.IS_REACTIVE];
}

get函数中相应的修改,

if (key === ReactiveFlags.IS_REACTIVE) {
  return !isReadonly;

isReadonly

有了isReactive的实现,isReadonly很类似。

isReadonly()检查传入的值是否为只读对象。只读对象的属性可以更改,但他们不能通过传入的对象直接赋值。

单测

readonly.spec.tshappy path测试用例中添加isReadonly的断言。

import { isReadonly, readonly } from "../reactive";
it("happy path"() => {
  const original = { foo: 1, bar: { bar: 2 } };
  const wapper = readonly(original);
  expect(wapper).not.toBe(original);
  expect(wapper.foo).toBe(1);

  // isReadonly
  expect(isReadonly(wapper)).toBe(true);
  expect(isReadonly(original)).toBe(false);
});

实现

reactive.ts中导出isReadonly方法

export const enum ReactiveFlags {
  IS_REACTIVE = "__v_isReactive",
  IS_READONLY = "__v_isReadonly",
}
export function isReadonly(value{
  return !!value[ReactiveFlags.IS_READONLY];
}

get函数中新增对readonly的判断

if (key === ReactiveFlags.IS_REACTIVE) {
  return !isReadonly;
else if (key === ReactiveFlags.IS_READONLY) {
  return isReadonly;
}

执行所有单测yarn test验证。

往期文章

搭建项目环境,集成ts和jest

reactive和effect,依赖收集触发依赖

完善effect功能

实现readonly,重构是一步步进行的


原文始发于微信公众号(前端一起学):实现Vue3中isReactive和isReadonly

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/191302.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!