shallowRef核心是只响应.value整体替换,不追踪内部变化,适用于大数据量、整块替换、仅展示等场景;需用.value赋值或triggerRef手动通知更新,配合computed缓存派生字段可进一步提升性能。

用 shallowRef 优化深层对象,核心是“只响应整体替换,不追踪内部变化”。它不是让大对象变快,而是让 Vue 别去管它的里子——省掉成百上千个 Proxy 初始化和依赖链,性能提升立竿见影。
什么情况该换 shallowRef?
满足以下任意一条,就值得试试:
- 数据结构很大(比如 5000+ 行表格、地图坐标数组、三维模型顶点)
- 你基本不修改内部字段,只整块替换(如分页加载新列表、切换主题配置)
- 你改了内部字段但不需要立刻更新视图(比如批量预处理数据)
- 数据来自后端 API,只是展示用,没有双向绑定或局部编辑需求
怎么写才不丢响应?
关键记两点:赋值要动 .value,改内部要配 triggerRef。
审查 Vue 管理后台的变更请求(Vue 2 + Element UI,Vue 3 + Element Plus)。重点关注最小化变更实现、上线风险检查以及回归检查清单生成。
- ✅ 正确触发更新:直接替换整个 value ——
list.value = newData - ❌ 不会触发更新:只改嵌套属性 ——
list.value[0].status = 'done' - ✅ 批量改完再通知:先改内部,最后调
triggerRef(list),一次更新
和 shallowReactive 怎么选?
看你是要 ref 语义还是 reactive 语义:
立即学习“前端免费学习笔记(深入)”;
- 用 shallowRef:需要配合
watch、computed或组合式函数,或者你习惯.value写法 - 用 shallowReactive:想直接访问属性(如
state.items),适合配置对象、扁平大对象 - 别混用:shallowRef 包的是普通对象,shallowReactive 返回的就是响应式对象,类型和行为都不同
搭配 computed 缓存派生数据
即使用了 shallowRef,模板里也不要写 {{ list.value[0]?.user?.profile?.name }} 这种长路径。每次渲染都走多层 getter,还无法缓存。
- 提前在 setup 里定义计算属性:
const firstUserName = computed(() => list.value[0]?.user?.name || '') - 组件里直接绑定
{{ firstUserName }},既安全又高效 - 如果 name 是静态的,甚至可以加
Object.freeze再传给 shallowRef,彻底跳过响应式处理

















