
直接用 markRaw 包裹不需要响应式追踪的对象,就能跳过 Vue 的 Proxy 代理过程,减少递归处理、内存占用和触发更新的开销。
哪些数据适合 markRaw?
核心判断标准:这个对象你确定它不会变,也不需要视图随它变化而更新。
- 第三方库实例(如 ECharts 实例、Leaflet 地图对象、WebGL 渲染器)
- 大型只读数据(如初始化后就固定的树形配置、国家地区列表、mock 表格数据)
- 静态组件定义(比如动态
<component :is="xxx"></component>中预设的组件对象) - 外部传入且不参与响应式逻辑的对象(如从插件、全局状态或服务端直出的结构化数据)
怎么写才有效?
必须在传入 reactive 或作为响应式对象属性赋值前标记。一旦被响应式系统包裹过,再用 markRaw 就不起作用了。
✅ 正确示例:
import { markRaw, reactive } from 'vue'
// 第一步:先 markRaw
const chartInstance = markRaw(new ECharts(dom))
const config = markRaw({ theme: 'dark', autoResize: true })
// 第二步:再放进 reactive
const state = reactive({
chart: chartInstance,
uiConfig: config,
list: markRaw(fetchStaticTableData()) // 大列表也一起标记
})
❌ 错误写法:
const rawObj = { x: 1 }
const reactiveObj = reactive(rawObj)
const stillReactive = markRaw(reactiveObj) // 无效!它已经是响应式代理了
要注意的边界情况
markRaw 只影响目标对象本身,不递归处理它的嵌套属性。
- 如果它内部引用了别的响应式对象(比如
markRaw({ a: ref(1) })),那个ref依然会响应 - 不能用于基础类型(字符串、数字、布尔值),只接受对象、数组、函数等引用类型
- 标记后无法通过
toRaw还原——它本来就没被代理过,toRaw对它没意义
配合 provide/inject 更安全
在跨组件共享第三方实例时,推荐在 provide 阶段就标记,避免下游无意中把它塞进自己的 reactive 中:
import { markRaw } from 'vue'
import ChartLib from 'chart.js'
export default {
setup() {
const chart = markRaw(new ChartLib())
provide('globalChart', chart) // 提供的是原始实例,无代理
return () => h('div')
}
}
不复杂但容易忽略:关键不在“用了没”,而在“什么时候用、谁来用、有没有提前用”。










