shallowRef 的核心作用是仅对 .value 赋值触发响应式更新,内部属性不代理、不收集依赖;适合整体替换的大数据源或第三方实例,配合 triggerRef 手动控制更新时机。

shallowRef 的核心作用就是绕过深层代理——它只让 .value 这一层的赋值具备响应性,内部所有属性完全不走 Proxy,自然也就没有递归代理、依赖收集和更新扩散这些开销。
只代理引用,不代理结构
当你写 const data = shallowRef(largeObject),Vue 不会对 largeObject 做任何遍历或包装。整个对象以原始形态存在,内存里就是一个普通 JS 对象。哪怕它有 5 层嵌套、10 万个属性,初始化瞬间就完成,零代理成本。
- 修改
data.value = newData→ 触发响应式更新 ✅ - 修改
data.value.items[0].status = 'done'→ 界面不刷新,也不触发依赖收集 ❌
配合 triggerRef 实现可控更新
局部改数据又想刷新视图?不用转成深度响应式,直接调用 triggerRef(data)。它相当于手动“按一下刷新键”,通知所有依赖这个 shallowRef 的副作用(比如组件渲染、watch)重新执行。
- 适合批量修改后统一触发,比逐个字段响应更高效
- 避免了为每个字段单独建立 Proxy 和依赖链
- 你掌握更新时机,系统不再“被动监听”
精准匹配使用场景
不是所有数据都该进响应式系统。shallowRef 最适合那些“整体换、少拆解”的数据:
从零开始编排 SpringBoot+Vue 全栈项目工作流,适用于新建全栈项目或完整脚手架请求,触发后依次调用 product‑spec‑builder(需求调研)等模块。
立即学习“前端免费学习笔记(深入)”;
- 万级表格数据源(分页/筛选时整页替换)
- ECharts / Three.js / wangEditor 等第三方实例(它们自己管状态)
- 接口返回的原始 JSON 配置(城市列表、菜单树、静态字典)
- 大型只读明细表(审计日志、操作记录)
和 markRaw 的分工要清楚
markRaw 是彻底标记“别动我”,连 .value 变化都不响应;shallowRef 是“只动顶层”。前者用于完全隔离(如 Canvas 上下文),后者用于“整体可更新但内部不动”。混用反而容易出错。
不复杂但容易忽略


















