Vue3 中的 markRaw 和toRaw和shallowRef

文章类型:Vue

发布者:hp

发布时间:2025-04-25

一:引言

在vue3中,增加很多API,那么markRaw 、toRaw、shallowRef他们的使用场景是什么呢?

二:区别

(一)markRaw

1:作用=>显式标记对象为「非响应式」,使其永远不会被 Vue 转换为响应式代理对象‌

2:原理=>通过添加 __v_skip 内部属性跳过代理转换流程‌

3:场景=>

   防止第三方库实例(如 ECharts、Three.js)被代理引发冲突‌

   优化静态数据(如大列表)性能,避免代理开销‌

   动态组件切换时避免组件实例被代理‌

(二)toRaw

1:作用=>返回由 reactive 或 ref 创建的响应式对象的‌原始对象‌,绕过代理直接操作数据‌

2:原理=>通过递归查找响应式对象的原始引用实现解包‌

3:场景=>

   需要临时修改响应式对象的原始数据且不触发视图更新‌

   与第三方库交互时需传递原始数据而非代理对象‌

(三)shallowRef

1:作用=>创建仅跟踪 .value 引用变化的响应式对象,‌不深度追踪内部属性‌变化‌

2:原理=>仅在 .value 被替换时触发更新,内部属性修改无响应‌

3:场景=>

   处理大型对象或数组时避免深度响应式转换的性能损耗‌

   动态组件切换时存储组件实例

三:代码

1:markRaw

import { reactive, markRaw } from 'vue';  
const thirdPartyObj = markRaw({ data: [...] }); // 标记为非响应式  
const state = reactive({  
  config: thirdPartyObj // 嵌套在响应式对象中仍保持原始状态  
});  

2:toRaw

import { reactive, toRaw } from 'vue';  
const proxy = reactive({ data: 1 });  
const raw = toRaw(proxy); // 获取原始对象  
raw.data = 2; // 修改不会触发视图更新  

3:shallowRef

import { shallowRef } from 'vue';  
const largeObj = shallowRef({ list: [...] });  
largeObj.value.list.push(1); // 内部修改不触发更新  
largeObj.value = { list: [...] }; // 替换整个对象触发更新  

四:总结

1:markRaw‌=>标记后的对象‌不可逆‌,无法通过 reactive 或 ref 恢复响应式‌。仅标记当前对象,‌嵌套属性仍可能被代理‌(需逐层标记)

2:toRaw‌=>仅对响应式对象有效,普通对象调用返回自身‌。修改原始对象可能导致与代理对象‌数据不一致‌,(谨慎操作‌)

3:shallowRef‌=>使用 .value 赋值新对象时才触发更新,内部属性修改需手动调用 triggerRef()‌