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

toRaw 与 markRaw

toRaw()

概念:toRaw() 可以返回由 reactive()、readonly()、shallowReactive() 或者 shallowReadonly() 创建的代理对应的原始对象

首先,我们都知道,  reactive()、 shallowReactive() 、readonly()或者 shallowReadonly() 这四个方法都是用来创建响应式对象,只不过是深层响应还是浅层响应的问题。

而 toRaw() 则是接收上面这四个方法定义的响应式对象,然后获取未经处理的原始对象。

let person = {name: "al",age: 28,job: {j1: {work: "前端",salary: 2,},},arr: [1, 2, 3],
};let reactivePer = reactive(person);
console.log(reactivePer);           // Proxy(Object) 深度响应对象
console.log(toRaw(reactivePer));    // 源对象 {name: 'al', age: 28, job: {…}, arr: Array(3)}let shallowReactivePer = shallowReactive(person);
console.log(shallowReactivePer);    // Proxy(Object) 浅层响应对象
console.log(toRaw(shallowReactivePer));// 源对象 {name: 'al', age: 28, job: {…}, arr: Array(3)}

 那么问题就来了,我的 ref() 函数 ,在定义对象类型的响应式数据时,其底层也是通过 reactive() 函数来实现响应式转化的。那如果我通过 ref() 定义的对象能否被 toRaw() 转化为原始对象么?

let person = {name: "al",age: 28,job: {j1: {work: "前端",salary: 2,},},arr: [1, 2, 3],
};let refPer = ref(person);// RefImpl 响应式对象
console.log(refPer);   // 经过ref转化的数据,在js中使用时需要.value ,
//返回原始对象 {name: 'al', age: 28, job: {…}, arr: Array(3)} 
console.log(toRaw(refPer.value));   

 测试可知,通过 ref() 定义的对象类型响应式数据,toRaw()函数也能返回原始对象

那么 toRaw() 函数能否 将 ref() 函数定义的基本类型数据返回原始对象么?

答案是不会,ref() 函数定义的基本类型的值,通过 toRaw() 转化之后,也只会得到初始值,而不是对象

let refSum = ref(0)// RefImpl 响应式对象
console.log(refSum);// refSum.value 值就是一个基础类型数据,所以返回的是原始值 0,并不是一个对象
console.log(toRaw(refSum.value));

但是这里需要注意一个问题,那就是 toRaw() 的单层处理:toRaw()只能作用于传入的那个对象本身,并将该对象还原为其未代理的原始对象。如果这个对象内部有嵌套的响应式对象,toRaw 不会自动递归处理这些嵌套的对象,也就是说它只会处理调用它时直接传入的那一层对象,而不会处理更深层次的嵌套对象。

还是之前的例子:

let person = {name: "al",age: 28,job: {j1: {work: "前端",salary: 2,},},arr: [1, 2, 3],
};let reactivePer = reactive(person);
console.log(reactivePer);           // Proxy(Object) 深度响应对象
console.log(toRaw(reactivePer));    // 源对象 {name: 'al', age: 28, job: {…}, arr: Array(3)}

在这个例子中,reactivePer是一个深度嵌套的响应式对象。reactivePer本身是响应式的,同时 jobj1、arr也是被代理的响应式对象。

当你调用 toRaw 时:toRaw() 将 reactivePer 还原成了person,即最初传入的那个非响应式对象

console.log(toRaw(reactivePer) === person);     // true

 但 toRaw 不会自动处理 reactivePer.job、 reactivePer.job.j1或 reactivePer.arr,它们仍然是响应式的,除非你单独对它们调用 toRaw

如果你只对某一层的嵌套对象调用 toRaw,例如:

const job = toRaw(reactivePer.job);console.log(job=== person.job);    // true
  • 这里,toRaw(reactivePer.job)job还原为 reactivePer.job,即未代理的原始对象。
  • reactivePer.job.j1 仍然是一个响应式对象,除非你也对它调用 toRaw

如果你希望获取整个嵌套对象的原始版本,你需要对每一层嵌套对象分别调用 toRaw

使用场景:

  1. 性能优化:在某些情况下,你可能不希望某些操作触发响应式更新,尤其是在处理大数据结构或频繁修改数据时。使用 toRaw 可以绕过响应式代理,直接操作原始数据,避免不必要的性能开销。
    const reactiveArray = reactive([1, 2, 3]);// 使用 toRaw 操作原始数组,不触发响应式更新
    toRaw(reactiveArray).push(4);
    
  2. 与第三方库集成:当你将 Vue 的响应式对象传递给不兼容响应式代理的第三方库时,可能会导致意外行为或错误。在这种情况下,可以使用 toRaw 将对象转换为原始对象后再传递给第三方库。
    import { reactive, toRaw } from 'vue';
    import thirdPartyLib from 'some-third-party-lib';const reactiveData = reactive({ name: 'Alice' });// 将原始数据传递给第三方库
    thirdPartyLib.processData(toRaw(reactiveData));
    
  3. 避免循环引用:在复杂的响应式对象结构中,可能会发生循环引用。通过使用 toRaw,可以避免在序列化或深度克隆对象时发生循环引用错误。

    import { reactive, toRaw } from 'vue';const obj = {};
    obj.self = obj;const reactiveObj = reactive(obj);// 序列化前将对象转换为原始对象,避免循环引用问题
    const jsonString = JSON.stringify(toRaw(reactiveObj));
    
  4. 对比原始数据:有时候你可能需要将一个响应式对象与其原始对象进行对比,来检查数据是否发生了变化。在这种情况下,toRaw 可以帮助你提取原始对象进行对比

    import { reactive, toRaw } from 'vue';const originalObj = { count: 0 };
    const reactiveObj = reactive(originalObj);// 检查响应式对象是否与原始对象相同
    if (toRaw(reactiveObj) === originalObj) {console.log('Objects are the same');
    }
    
  5. 克隆响应式对象:当你需要克隆一个响应式对象时,可以使用 toRaw 提取原始对象,然后进行深度克隆,以避免响应式特性被克隆。

    import { reactive, toRaw } from 'vue';
    import cloneDeep from 'lodash/cloneDeep';const reactiveObj = reactive({ count: 0 });// 使用 toRaw 提取原始对象,然后进行深度克隆
    const clonedObj = cloneDeep(toRaw(reactiveObj));
    

markRaw()

概念:将一个对象标记为不可被转为代理。返回该对象本身。

用于标记某个对象为“原始对象”(非响应式对象),从而确保该对象不会被 Vue 的响应式系统代理。这意味着当你使用 markRaw 处理一个对象后,即使将它传递给 reactiveref,该对象仍然保持原样,不会被转换为响应式对象。

let person = {name: "al",age: 28,job: {j1: {work: "前端",salary: 2,},},arr: [1, 2, 3],
};let markRawPer = markRaw(person);let reactivePer = reactive(markRawPer);
console.log(reactivePer === person);    // true,reactive定义的数据与原始数据完全相同let refPer = reactive(markRawPer);
console.log(refPer === person);        // true,ref定义的数据与原始数据完全相同

使用场景:

  1. 第三方库的数据对象:当你使用第三方库时,这些库的数据结构通常不需要响应式处理。如果你希望这些数据对象在 Vue 组件中使用时不触发响应式系统,可以使用 markRaw
    import { markRaw, reactive } from 'vue';// 假设这是来自第三方库的数据对象
    const thirdPartyData = markRaw({ name: 'Alice', age: 30 });// 即使将它包裹在 reactive 中,它也不会变成响应式对象
    const state = reactive({user: thirdPartyData
    });// 更改 thirdPartyData 的属性不会触发 Vue 响应式系统
    state.user.age = 31; // 不会触发响应式更新
    
  2. 性能优化:在某些情况下,你可能有大量的静态数据不需要响应式处理。通过使用 markRaw,可以避免 Vue 进行不必要的代理,从而提升性能。类似于 Vue2中的冻结数据

    import { markRaw, reactive } from 'vue';const largeStaticData = markRaw({items: [/* 大量数据 */]
    });const state = reactive({data: largeStaticData
    });// `largeStaticData` 不会触发响应式系统,减少性能开销
    
  3. 避免循环引用:案例同上

总结

1、toRaw:将一个响应式对象转为原始对象,ref定义的基础类型数据不会被转换

2、toRaw:单层处理,toRaw()只能作用于传入的那个对象本身,并将该对象还原为其未代理的原始对象。如果你希望获取整个嵌套对象的原始版本,你需要对每一层嵌套对象分别调用 toRaw

3、toRaw使用场景:包括但不限于性能优化、第三方库集成、避免循环引用、对比原始数据、克隆响应式对象等

4、markRaw :标记某个对象为“原始对象”(非响应式对象),从而确保该对象不会被 Vue 的响应式系统代理。

5、markRaw 使用场景:包括但不限于性能优化、第三方库集成、避免循环引用等

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【机器学习】逻辑回归
  • ArcGIS Pro基础:如何将数据和引用地图样式一起打包分享
  • leetcode53:最大子数组和
  • Neo4J下载安装
  • 宿州申报!宿州市首台套重大技术装备申报奖补条件
  • 39-nacos eureka zookeeper区别
  • 飞书应用机器人文件上传
  • 【C++】12.智能指针
  • Jupyter Notebook 使用多个Kernel
  • 技术文档索引
  • Linux 内核源码分析---组播/策略路由选择
  • 内存函数memcpy和memmove
  • 谷歌chrome浏览器显示“版本太旧”又无法更新情况下,如何关闭“Chrome版本太旧”提示,包括直接启动Google浏览器,或者通过其他应用启动
  • Web层统一实体规范封装
  • 出现 2003 - Can’t connect to MySQL server on ‘xxx‘(10060) 解决方法
  • [笔记] php常见简单功能及函数
  • Cookie 在前端中的实践
  • Druid 在有赞的实践
  • Elasticsearch 参考指南(升级前重新索引)
  • JavaScript实现分页效果
  • laravel with 查询列表限制条数
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • ubuntu 下nginx安装 并支持https协议
  • Vue实战(四)登录/注册页的实现
  • vue数据传递--我有特殊的实现技巧
  • Work@Alibaba 阿里巴巴的企业应用构建之路
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 思考 CSS 架构
  • 跳前端坑前,先看看这个!!
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • const的用法,特别是用在函数前面与后面的区别
  • 仓管云——企业云erp功能有哪些?
  • 策略 : 一文教你成为人工智能(AI)领域专家
  • 回归生活:清理微信公众号
  • 说说我为什么看好Spring Cloud Alibaba
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • # dbt source dbt source freshness命令详解
  • #define与typedef区别
  • #if 1...#endif
  • #includecmath
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第14章泛型第2节(泛型类的类构造函数)
  • (SpringBoot)第二章:Spring创建和使用
  • (vue)el-tabs选中最后一项后更新数据后无法展开
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (附源码)计算机毕业设计ssm电影分享网站
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (十三)Maven插件解析运行机制
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .net core webapi 大文件上传到wwwroot文件夹