ref 默认深度响应式,大型嵌套对象会导致初始化慢、内存高、访问慢;应改用 shallowref 或 markraw 规避开销。

用 ref 本身不会自动避免响应式开销——它默认就是深度响应式的。真正能规避不必要开销的,是换用 shallowRef,或者配合 markRaw 使用。
什么时候 ref 会带来性能问题
当你把一个大型嵌套对象(比如含上千项的数组、三维模型数据、完整 API 响应体)直接传给 ref() 时,Vue 会递归遍历整个结构,为每一层对象、数组、属性都创建 Proxy 代理。这导致:
- 初始化耗时明显增长,尤其在组件挂载或数据首次赋值时
- 内存占用升高,成百上千个 Proxy 实例被同时创建
- 后续访问任意深层字段(如
data.items[0].meta.id)都要触发 Proxy 的 get 拦截,比原生对象慢 2–5 倍 - 你其实只关心“整个对象被替换了”,却为每次内部字段读写都付出了响应式成本
用 shallowRef 替代 ref 处理大对象
shallowRef 只监听 .value 引用本身的变化,不对内部做任何响应式转换。适合那些“整体替换才需更新视图”的场景。
审查 Vue 管理后台的变更请求(Vue 2 + Element UI,Vue 3 + Element Plus)。重点关注最小化变更实现、上线风险检查以及回归检查清单生成。
- 地图应用中的覆盖物集合(
shallowRef([{lat: ..., lng: ...}, ...])) - 表格的原始数据源(
shallowRef(apiResponse.data)),分页/筛选时整批替换 - 富文本编辑器的内容快照、Canvas 图形数据等不可变结构
- 注意:
shallowRef.value.xxx = yyy不会触发更新,必须赋新值:shallowRef.value = newData
对纯静态配置用 markRaw 配合 ref
如果某段数据完全不会变更(如主题色配置、i18n 字典、第三方 SDK 实例),就别让它进响应式系统:
- 先用
markRaw标记,再传给ref或reactive - 例如:
const theme = ref(markRaw({ primary: '#409eff', borderRadius: '4px' })) - 这样 Vue 完全跳过它的 Proxy 包装和依赖收集,零开销
- 适用于常量对象、枚举、全局配置、已封装好的类实例
别解构 ref,否则响应性就丢了
直接写 const { count, name } = myRef.value 会得到普通 JS 值,修改它们不会触发更新。正确做法是:
- 保持
.value访问,或 - 用
toRefs处理 reactive 对象;但 ref 本身不支持 toRefs,所以大对象优先走 shallowRef + 显式赋值 - 模板中始终用
{{ myRef.value.field }},逻辑里也尽量避免提前解构
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!









