Vue 3 非响应式逃生舱:markRaw、toRaw 与 shallow 系列的正确分工

test12026-11-011 次阅读

响应式不是免费的

Vue 的 reactive 会把对象递归地包成 Proxy。问题是:遇到第三方实例(图表、编辑器)、超大数组、或者你根本不想追踪变化的对象,深度代理既浪费性能也可能让第三方库出错。Vue 提供了一组“逃生舱”:markRaw、toRaw、shallowRef、shallowReactive。关键不是会不会用,而是分清各自的分工。

markRaw:告诉 Vue 别代理这个对象

echarts、monaco、mapbox 这类库返回的是自带内部状态的实例,一旦被 reactive 递归包裹就会报错或卡顿。用 markRaw 包一层,Vue 就不会去代理它。

import { markRaw, onMounted, ref } from 'vue'
import * as echarts from 'echarts'

const el = ref(null)
let chart

onMounted(() => {
  // 关键:markRaw 防止 echarts 实例被变成响应式 Proxy
  chart = markRaw(echarts.init(el.value))
  chart.setOption({ /* ... */ })
})

shallowRef:只追踪引用替换

当你要替换的是一整个大列表,而不是逐个改元素,用 shallowRef 只监听 .value 的重新赋值,跳过深层比对,渲染更快。

import { shallowRef } from 'vue'

const list = shallowRef([])

// 必须整体替换引用才会触发更新
async function load() {
  const data = await fetchBigList()
  list.value = data
}

toRaw:临时拿回原始对象

在需要把响应式对象直接交给第三方库(比如传给表单校验器、序列化)时,用 toRaw 拿到没有被 Proxy 包裹的原始引用,避免库读到奇怪的代理字段。

import { reactive, toRaw } from 'vue'

const form = reactive({ name: '张三', age: 20 })
const plain = toRaw(form) // 普通对象,不含 Proxy 开销
// 传给只认普通对象的旧库
legacyValidate(plain)

怎么选

  • 第三方实例、不该被追踪的对象:markRaw。
  • 大对象只换不改、追求更新速度:shallowRef / shallowReactive。
  • 临时绕过响应式、把数据交出去:toRaw。

记住一条:响应式是为了让 UI 跟着变,不是为了追着每一个字节。分不清边界,才会写出又慢又怪的代码。

T

test1

文章作者

响应式不是免费的 Vue 的 reactive 会把对象递归地包成 Proxy。问题是:遇到第三方实例(图表、编辑器)...

分类
技术
发布时间
2026-11-01
字数
约 1204 字
阅读
1 次