shallowRef 用于 Vue 单文件组件中精准控制响应边界,仅对顶层数据响应,跳过深层字段的 Proxy 初始化;修改需赋值 .value,内部字段变更不响应,可配合 triggerRef 主动触发更新,并与 markRaw 协同处理不可响应对象。

在 Vue 单文件组件中用 shallowRef 优化深层嵌套,关键是让响应式只作用于你真正需要更新的层级,跳过内部字段的 Proxy 初始化和依赖收集。它不是“禁用响应式”,而是“精准控制响应边界”。
只对整块数据做顶层响应
当某个嵌套对象整体作为不可变单元使用(比如表格原始数据、菜单配置、API 快照),你只会在切换页、刷新列表、替换整个结构时才需要触发更新,那就该用 shallowRef:
- 用
shallowRef(data)替代ref(data)或reactive(data) - 修改时必须赋值给
.value,例如list.value = newData才会触发更新 - 直接改内部字段如
list.value[0].status = 'done'不会响应——这正是你要的效果
配合 triggerRef 主动通知变更
有时你确实需要在不替换整个对象的前提下“告诉 Vue:这部分内容变了”,比如手动更新了 shallowRef 包裹对象的某个字段:
Vue 3 组合式 API 与 最佳实践,涵盖代码组织、useXxx 模式、组合式函数设计、Store 集成、响应式优化及功能抽取。
- 调用
triggerRef(ref)强制触发依赖更新 - 适合场景:第三方库返回的对象(如 ECharts 实例、Three.js 场景)、或你用
Object.assign修改了内部状态 - 注意不要滥用——频繁调用等于手动模拟响应式,应优先考虑是否真需响应
与 markRaw 协同处理复杂对象
如果嵌套结构里包含函数、循环引用、或来自外部库的实例(如 new Date()、Map、图表实例),它们本身就不该进响应式系统:
立即学习“前端免费学习笔记(深入)”;
- 先用
markRaw()标记这些子对象,再传给shallowRef - 例如:
const config = shallowRef(markRaw({ renderHeader: h => h('div') })) - 这样既避免 Proxy 报错,又防止无意义的 getter 拦截开销
模板中安全读取 + 计算属性兜底
shallowRef 不影响你在模板里访问字段,但要注意写法:
- 模板中仍可写
{{ list.name }}或{{ list.items[0].title }},Vue 会自动解包 .value - 但为防空值或深层路径报错,建议用
computed封装安全读取逻辑 - 例如:
const displayName = computed(() => props.data?.user?.profile?.name || '')

















