markRaw() 是 Vue 3 提供的一个 响应性系统工具函数,它的作用是:
👉 标记一个对象为 “不可被 Vue 响应式系统追踪” 的原始对象。
使用 markRaw(obj) 后,这个对象就不会再被 reactive() 或 ref() 转换为响应式对象了。
例子
import { reactive, markRaw } from 'vue'
const myChart = markRaw(new EChartsInstance()) // 不需要被追踪
const state = reactive({
count: 0,
chart: myChart
})
为什么要这么做?🔍
如果你把一个 第三方库对象(比如 ECharts、Mapbox、Three.js 实例等)交给 Vue 的响应式系统去追踪,会导致:
- 不必要的性能开销;
- 某些库对象内部是非响应式友好的(含闭包、DOM 引用等),会报错或异常。
所以用 markRaw() 标记后,Vue 就 不再试图将它转换为响应式对象,你可以正常使用它而不引发副作用。
和 shallowReactive()的区别📌
| 特性 | markRaw | shallowReactive |
|---|---|---|
| 作用范围 | 完全不响应式 | 只对顶层属性响应式 |
| 返回值 | 原对象本身 | 新的响应式代理对象 |
| 使用场景 | 第三方实例 / DOM | 层级很浅的状态对象 |
| 能否被嵌套追踪 | ❌ 永远不会 | ✅ 嵌套层级不可追踪,但顶层可响应 |
源码分析(简化版)🧬
markRaw 的实现非常简单:
const RAW_FLAG = '__v_skip'
export function markRaw<T extends object>(value: T): T {
def(value, RAW_FLAG, true)
return value
}
它就是往对象上加一个 __v_skip 的标记,告诉 Vue 的响应式系统 跳过这个对象:
function isRaw(obj) {
return obj && obj.__v_skip === true
}
在执行 reactive(obj) 时,Vue 会检查这个标记,如果存在就跳过。
📦 常见使用场景
| 场景 | 示例 |
|---|---|
| 📊 图表库实例 | ECharts、Highcharts、Chart.js |
| 🗺️ 地图库对象 | Leaflet、Mapbox、Cesium |
| 🎮 3D 渲染对象 | Three.js、Babylon.js |
| 📦 大型数据缓存对象 | 不需要 UI 响应的大对象缓存 |
| 🧱 DOM 元素 | markRaw(document.createElement('div')) |
如果你在项目中使用到了 ECharts、音频 API 或者 Bluetooth 的实例对象,那一定要记得 markRaw 保护它们不被 Vue 干扰! shallowReactive() 是 Vue 3 中提供的一个创建“浅层响应式”对象的方法。它只会让对象的最外层属性变成响应式,但内部嵌套对象不会递归转为响应式。
shallowReactive 🧠
shallowReactive:只追踪外层属性的响应式状态,内层对象保持原样(非响应式) 。
示例一:避免嵌套结构递归转响应式📦
import { shallowReactive } from 'vue'
const state = shallowReactive({
count: 0,
info: {
name: 'Vue',
age: 3
}
})
// ✅ 外层 count 是响应式的
state.count++
// ❌ 内层 info.name 不是响应式的
state.info.name = 'Vue 3'
// 这个不会触发视图更新!
所以对 state.info.name 的修改,不会被 Vue 追踪到。只对 state.info = {} 这样的顶层替换才有效。
示例二:配合第三方库(比如 DOM)📦
const state = shallowReactive({
el: document.createElement('div')
})
// el 是 DOM 元素,Vue 不会对它做响应式转换,防止副作用
示例三:避免不必要的性能开销 📦
const config = shallowReactive({
// 大型配置对象,不需要深层响应式
settings: {
theme: 'dark',
layout: 'grid',
data: new Array(10000).fill(0)
}
})
// 只关心 settings 这块被整体替换,不关心它里面的数据项是否响应式
🚫 注意事项:
- 它不会深度追踪属性变更,比如数组项、对象属性更新;
- 对象嵌套较深时,不要误以为所有属性都响应式;
- 若需要深层追踪,请使用 reactive()。