vue3 响应式API toRaw() 和 markRaw()

toRaw()

toRaw()根据一个 Vue 创建的代理返回其原始对象。

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

官网描述:这是一个可以用于临时读取而不引起代理访问/跟踪开销,或是写入而不触发更改的特殊方法。不建议保存对原始对象的持久引用,请谨慎使用。

示例:

import { reactive, toRaw } from 'vue';
const reactiveObj = reactive({ message: 'Hello' });
const rawObj = toRaw(reactiveObj);
console.log(rawObj); // 输出原始对象,没有响应式的特性

在这里插入图片描述
toRaw接受一个响应式对象作为参数,并返回该对象的原始版本,即没有被 Vue 的响应式系统包裹的版本。

使用场景

在需要将响应式对象传递给非 Vue 的库或外部系统时,使用 toRaw() 可以确保它们收到的是普通对象。

markRaw()

markRaw()将一个对象标记为不可被转为代理,使其永远不会变成响应式的。即使这个对象被传递给reactiveref等响应式函数,它也不会被转换为响应式对象。

markRaw()接受一个对象作为参数,并且返回该对象本身。

import { markRaw, reactive } from 'vue';
const normalObj = { message: 'Hello' };
const markedObj = markRaw(normalObj);
const reactiveObj = reactive(markedObj);

console.log(reactiveObj); // 输出的对象仍然是非响应式的,不会触发依赖追踪和更新
console.log(isReactive(reactiveObj)) // false

const changeReactiveObjMsg = () => {
  // 不会触发响应式更新,因为 reactiveObj 被标记为非响应式
  reactiveObj.message = 'Change Reactive message!'
}

通过Vue Devtools查看setup里的数据:
从下图可以看出,reactiveObj是一个普通的对象,不是被Proxy包裹的响应式对象。
在这里插入图片描述

markRaw()是浅层的

markRaw()的作用是浅层的,这意味着它只会影响直接传入的对象本身,而不会递归地处理对象的嵌套属性。

  • 当使用 markRaw() 标记一个对象时,只有这个对象本身被标记为非响应式
  • 如果这个对象包含嵌套的对象或数组,这些嵌套的内容不会被自动标记为非响应式。
import { markRaw, reactive } from 'vue';
// 尽管 markedObj 被标记为了原始对象,但 markedObj.details 却没有
const markedObj = markRaw({
  name: '张三',
  age: 18,
  details: {
    address: '四川省成都市'
  }
});

// foo 是原始对象
const foo = reactive(markedObj);

// bar 是响应式对象
const bar = reactive({
  id: 'bar',
  details: markedObj.details
});

console.log(foo.details === bar.details)  // false

通过Vue Devtools查看setup里的数据:
在这里插入图片描述

使用场景

  1. 有些值不应该是响应式的,例如复杂的第三方类实例或 Vue 组件对象。
  2. 当呈现带有不可变数据源的大型列表时,跳过代理转换可以提高性能。
### Vue3 `toRaw` `markRaw` 的区别及用法 #### 定义与功能差异 `toRaw` 函数用于获取由 `reactive()` 或其他响应式 API 创建的对象的原始版本。这使得开发者可以直接操作该对象而不触发任何视图更新机制[^1]。 ```javascript import { reactive, toRaw } from 'vue'; const state = reactive({ count: 0 }); let rawState = toRaw(state); console.log(rawState === state); // false ``` 另一方面,`markRaw` 是用来标记一个对象使其永远保持非响应式的状态。即使后续尝试将其转换成响应式对象也不会成功;它会保留其原有的属性行为特性不变[^2]。 ```javascript import { markRaw, reactive } from 'vue'; const nonReactiveObj = markRaw({ name: 'Alice' }); const objWrapper = reactive(nonReactiveObj); // 尝试修改包装后的对象不会影响到DOM或其他依赖它的组件重新渲染 objWrapper.name = 'Bob'; console.log(objWrapper.name); // Bob (仅限于当前实例内部变化) ``` #### 使用场景对比 对于那些需要与外部库或原生 JavaScript 功能协同工作的部分来说,`toRaw` 提供了一种简单的方法来绕过 Vue 的反应系统并直接处理基础数据结构[^4]。而当面对某些特定类型的资源(比如复杂的第三方类实例),如果希望它们在整个应用生命周期内都维持为非响应性的,则应该考虑使用 `markRaw` 来防止不必要的性能开销以及潜在的数据同步问题[^3]。 #### 实际案例分析 假设有一个图表库 Chart.js 需要接收纯 JS 对象作为配置参数,在这种情况下就可以利用 `toRaw` 方法传递未经修饰过的原始数据给 chart 库: ```javascript function updateChart(chartConfig) { const rawData = toRaw(chartConfig); myChart.update(rawData); } ``` 而对于像 Lodash 这样的工具链中的不可变集合类型(Immutable Collections),由于这些对象已经具备高效的内部实现方式,因此没有必要再额外施加一层响应性包裹层,此时就适合采用 `markRaw` 处理: ```javascript import _ from 'lodash-es'; const immutableCollection = _.chain([/* ... */]).map(/*...*/).value(); export default markRaw(immutableCollection); ``` 通过上述例子可以看出,合理运用这两个方法可以帮助开发人员更好地控制程序逻辑,并优化整体性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值