shallowref 和 shallowreactive 是 vue 3 针对大型深层对象的性能优化方案,仅在顶层建立响应式联系,避免递归代理以降低开销;适用场景包括第三方不可变实例、巨型只读数据、首层更新为主的对象或数组,并需配合 triggerref、顶层赋值、按需 reactive 等手动控制策略。

Vue 3 中,shallowRef 和 shallowReactive 是专为大型深层对象设计的性能“减负开关”——它们跳过递归代理,只在顶层建立响应联系,从而大幅减少 Proxy 创建、依赖收集和内存占用。用对了,5000 条数据初始化耗时可降 40%~60%。
什么时候该选 shallowRef
适合需要保留 .value 访问习惯、且数据整体替换频繁、内部极少修改的场景:
- 存储第三方不可变实例:如 ECharts 实例、Mapbox 地图对象、Three.js 场景——这些对象内部不该被 Vue 代理,只需整个引用替换时触发更新
- 接收巨型只读响应体:比如后端返回含 10 万条日志的数组或复杂图表原始数据,你只做
data.value = response.data,从不改data.value[0].timestamp - 混合类型容器:例如
shallowRef({ count: 1, config: {}, instance: null }),避免 Vue 自动对config调用reactive导致意外代理
什么时候该选 shallowReactive
适合结构庞大但更新集中在第一层属性的普通对象或数组:
- 表格数据源:如
const tableData = shallowReactive([{ id: 1, name: '张三' }, ...5000 条]),每次翻页直接赋新数组tableData = newPageData,不改tableData[0].name - 配置对象:如
const config = shallowReactive({ theme: 'dark', api: { baseUrl: '' } }),模板里只读{{ config.theme }},不访问config.api.baseUrl - 树形列表根节点:父级折叠/展开、排序、筛选都通过替换整个
treeRoot完成,子节点(如children)基本只读
关键操作要领:浅 ≠ 无响应,而是由你掌控时机
深层改动不会自动触发更新,但你可以精准干预,不牺牲可控性:
- 对
shallowRef修改了.value内部字段后,调用triggerRef(ref)手动刷新一次(比逐条赋值高效得多) - 对
shallowReactive修改了深层属性(如state.user.profile.city),直接重新赋值顶层对象:state = { ...state, user: { ...state.user, profile: { ...state.user.profile, city: '深圳' } } } - 若某子结构确实需响应式(如正在编辑的单个用户),可单独对其调用
reactive(item),按需增强,不污染全局 - 模板中避免写
{{ user.profile.address.city }}这类深层路径;提前用computed或 store getter 暴露为顶层字段更安全、更高效
配合其他策略效果更佳
单靠浅响应式还不够,搭配使用能进一步释放性能:
- 对静态中间结构(如地址对象、枚举配置)用
Object.freeze(),彻底跳过响应式转换 - 将嵌套关系扁平化:把
users: { u1: { profile: { city: '北京' } } }拆成users: [...]、profiles: Map、addresses: [],用 ID 关联,组件只订阅自己关心的部分 - 对“可能展开”的深层结构(如树节点的
children)采用懒代理:初始存为普通对象,用户点击展开时再用reactive包裹对应子节点
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










