Vue3 —— reactive 全家桶及源码学习

  • 该文章是在学习 小满vue3 课程的随堂记录
  • 示例均采用 <script setup>,且包含 typescript 的基础用法

前言

上一篇学习了 ref 全家桶,在此基础上一起学习下 reactive 全家桶

一、reactive 对比 ref

  • ref 可以接收 所有类型reactive 只能接收 object类型(array、object、Map、Set)
  • ref 在取值和赋值时都要通过 .valuereactive不需要
  • reactive 不能直接整体赋值,因为它是通过 proxy 创建的响应式对象,直接赋值会 破坏响应式
    • 解决方案 1:可以 调用一些原生操作,比如 数组可用 push、pop 等去修改
    • 解决方案 2:外面再包上一层

① 创建

import { reactive } from "vue";

// object类型
const form = reactive({
  name: "xiaoman",
  age: 18,
});

// array类型
const list = reactive<string[]>([]);

② 修改

// 错误。直接整体赋值会破坏响应式
// list = ["a", "b", "c"];

// 可以通过原生方法去操作数据,不会破坏响应式
setTimeout(() => {
  const res = ["jay chou", "jolin"];
  list.push(...res);
}, 1000);

// 或者在外面包一层,这样对 obj.list 就可以整体赋值了
const obj = reactive<{ list: string[] }>({
  list: [],
});
setTimeout(() => {
  obj.list = ["a", "b", "c"];
}, 2000);

二、将 reactive 的值 设置为 readonly

  • 设置为 readonly 后不可修改
  • 修改 reactive 源数据,readonly 的值也会受影响
const info = reactive({
  name: "xiaoman",
});
const rd = readonly(info);

// 设置为 readonly 后不可修改
// rd.name = 'daman'

// 但是可以修改它的源数据
info.name = "blue";
console.log("修改源数据,readonly的值也会受影响", info, rd);

可以看到,两者的值都被修改了:

在这里插入图片描述

三、shallowReactive

  • 与上一篇 ref 全家桶shallowRef 十分相似,都是浅层的响应式
  • 修改第一层会触发视图更新,修改深层 不会触发视图更新
  • 有其他触发视图更新的操作,也会顺带将其更新

① reactive 是深层的响应式,视图会立刻更新

const obj2 = reactive({
  foo: {
    bar: {
      name: "xiaoman",
    },
  },
});
setTimeout(() => {
  obj2.foo.bar.name = "blue222222222";
}, 1000);

在这里插入图片描述

② shallowReactive 是浅层的响应式

const obj3 = shallowReactive({
  foo: {
    bar: {
      name: "xiaoman",
    },
  },
});
1、修改浅层才会触发响应式,会立刻更新:
setTimeout(() => {
  obj3.foo = {
    bar: {
      name: "小满",
    },
  };
}, 1000);
2、修改深层可以打印到新值,但视图不会立刻更新:
setTimeout(() => {
  // 修改深层不会触发更新
  obj3.foo.bar.name = "blue3333333333";
  console.log("obj3", obj3); // 打印成功,但是视图不会更新
}, 1000);

控制台:

在这里插入图片描述

视图:

在这里插入图片描述

3、会被其他有视图更新的操作,顺带着一起更新掉
setTimeout(() => {
  // 修改深层不会触发更新
  obj3.foo.bar.name = "blue3333333333";
  console.log("obj3", obj3);
  
  obj2.foo.bar.name = "blue555555"; // obj2 是 reactive,触发更新视图
}, 1000);

在这里插入图片描述

四、源码学习

主要关注 createReactiveObject 函数的逻辑

在这里插入图片描述
学习笔记:

/**
 *
 * 1、reactivity.d.ts中,关于 reactive 的类型定义:
 * 
 *    export declare function reactive<T extends object>(target: T): UnwrapNestedRefs<T>;
 *    
 * 	  其中 T extends object:即只能传入 object 的子类型
 * 
 * 2、reactivity.cjs.prod.js中,
 * 
 *      function reactive(target) {
          if (isReadonly(target)) {
            return target;
          }
        .....
        
 *      即:reactive 如果传入只读类型的,会直接返回
 *          
 *   3、createReactiveObject 函数中,
 *     - 若传入的不是 object 类型,会抛出警告(dev环境)并直接返回;
 *     - 若传入的是被 proxy 代理过的(并且不是为了将其变为只读),也会直接返回
 *     - 如果能从缓存中找到,则直接返回(weakMap)
 *     - 如果在白名单中,也会直接返回,例如 __skip__(后面会讲的 markRaw 处理过的会加一个 __skip__,会跳过proxy代理 )
 *     - 如果以上条件都没触发,就会进行 proxy代理
 *
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值