markraw用于防止vue错误代理非响应式对象。需标记第三方库实例、静态配置、需保持原始引用的对象,且不递归子属性,应逐层控制或配合shallowreactive使用。

当对象不需要响应式更新、又可能被意外代理时,就该用 markRaw。它不是“优化选项”,而是防止 Vue 错误劫持的必要手段。
第三方库实例必须标记
像 ECharts、Three.js、Leaflet、Canvas 2D 上下文这类对象,内部依赖原始引用、自有 getter/setter、Symbol 属性或原型方法。一旦被 Proxy 包裹,会出现:
-
=== 判断失败:
chart === chart可能返回false -
方法调用异常:如
chart.setOption()内部逻辑被拦截 - 视图反复重绘或卡顿:Proxy 触发多余依赖收集
- 内存泄漏风险:代理对象与库自身引用关系错乱
正确做法是初始化后立刻标记:
const chart = markRaw(echarts.init(dom))const scene = markRaw(new THREE.Scene())const ctx = markRaw(canvas.getContext('2d'))
静态配置与只读数据值得豁免
API 地址表、状态枚举、语言包、主题配置等,初始化后不再变更,却常含上百甚至上万字段。Vue 对它们递归建代理纯属浪费:
- 内存占用翻倍(每个属性对应 WeakMap 条目)
- 初始化耗时激增(例如 5000 节点树从 184ms 降至 17ms)
- 后续任何访问都多一层 Proxy 拦截开销
示例:
const STATUS_MAP = markRaw({ 1: '待审核', 2: '已通过' })const API_CONFIG = markRaw({ baseURL: '/v2', timeout: 10000 })
需要保持原始引用的对象
某些场景下,你依赖的是对象本身的恒定身份,而非其响应性:
-
new Map()或new Set():需保持原生迭代和方法行为 -
new Date()或new RegExp():代理后失去 instanceof 和原型方法 - 自定义 class 实例:方法调用、私有字段、getter/setter 均可能失效
- DOM 元素或组件对象:传递给第三方库时必须是原始引用
这些对象若混入 reactive,会被替换成代理,导致引用不一致问题。
嵌套结构要逐层控制
markRaw 只作用于目标对象本身,不自动递归子属性。例如:
-
const config = markRaw({ theme: 'dark', data: { x: 1 } })→config不响应式,但config.data仍是普通对象 - 若后续把
config.data赋给reactive({}),它仍会被代理
整棵树豁免有两种方式:
- 对每个需跳过的子级单独调用
markRaw - 改用
shallowReactive控制代理深度
判断是否生效,可用 isReactive(config) 验证,返回 false 即成功。










