reactive 全家桶及源码学习

reactive 全家桶及源码学习本文介绍了 Vue 中 reactive 和 ref 的区别 强调了整体赋值对响应式的影响以及如何通过 push 方法和将数组作为对象属性来解决

大家好,欢迎来到IT知识分享网。

前言

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

一、reactive 对比 ref

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

二、直接整体赋值会破坏响应式

import { 
    reactive } from "vue"; let arr = reactive<number[]>([]); setTimeout(() => { 
    arr = [1, 2, 3]; console.log(arr); // 数据变化了,但模板没变化 }, 100); 

2.1. 解决方法一:使用push方法

import { 
    reactive } from "vue"; let arr = reactive<number[]>([]); setTimeout(() => { 
    const newArr = [1, 2, 3]; arr.push(...newArr); console.log(arr); }, 100); 

2.2. 解决方法二:将数组定义为对象中的一个属性

import { 
    reactive } from "vue"; type T = { 
    arr: Array<number>; }; let list = reactive<T>({ 
    arr: [], }); setTimeout(() => { 
    list.arr = [1, 2, 3]; console.log(list.arr); }, 100); 

三、将 reactive 的值 设置为 readonly

  • 设置为 readonly 后不可修改
  • 修改 reactive 源数据,readonly 的值也会受影响
<script setup lang="ts"> import { 
    reactive, readonly } from "vue"; const info = reactive({ 
    name: "xiaoman", }); const rd = readonly(info); // 设置为 readonly 后不可修改 // rd.name = 'daman' // 但是可以修改它的源数据 info.name = "blue"; console.log("修改源数据,readonly的值也会受影响", info, rd); </script> 
  • 可以看到,两者的值都被修改了:
    在这里插入图片描述

四、shallowReactive

与上一篇 ref 全家桶 中 shallowRef 十分相似,都是浅层的响应式
修改第一层会触发视图更新,修改深层不会触发视图更新,有其他触发视图更新的操作,也会顺带将其更新(官方回复这并不是一个bug,而是特色)

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

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

在这里插入图片描述

4.2. shallowReactive 是浅层的响应式

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

4.3. 会被其他有视图更新的操作,顺带着一起更新掉

import { 
    reactive, shallowReactive } from "vue"; const obj2 = reactive({ 
    foo: { 
    bar: { 
    name: "xiaoman", }, }, }); const obj3 = shallowReactive({ 
    foo: { 
    bar: { 
    name: "xiaoman", }, }, }); setTimeout(() => { 
    // 修改深层不会触发更新 obj3.foo.bar.name = "blue"; console.log("obj3", obj3); obj2.foo.bar.name = "blue"; // obj2 是 reactive,触发更新视图 }, 1000); 

在这里插入图片描述

五、源码学习

主要关注 createReactiveObject 函数的逻辑

在这里插入图片描述

5.2. 学习笔记

/ * * 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代理 * */ 

六、toRef、toRefs、toRaw

toRef、toRefs、toRaw

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/146903.html

(0)
上一篇 2025-04-11 16:33
下一篇 2025-04-11 16:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信