shallowref 用于避免深层响应式代理,适用于只关心整体替换的大数据结构;需配合 markraw 和 triggerref 实现高性能控制。

shallowRef 在 Vue 3 中不是用来“替代 ref”的,而是专门解决一类性能瓶颈:当数据结构庞大、嵌套深、但你只关心整体替换(而非内部属性变化)时,它能跳过深层响应式代理,大幅减少初始化开销和内存占用。配合组合式 API,关键在于“明确意图 + 精准触发”。
什么时候该用 shallowRef 而不是 ref
判断标准很直接:你是否需要监听对象内部字段的修改?如果答案是否定的,就该考虑 shallowRef。
- 表格展示几千条静态配置项,仅需整体换页或刷新数据,不支持行内编辑
- 第三方图表实例(如 ECharts、Three.js 场景),只需挂载/销毁,不对其内部状态做响应式追踪
- 大型 JSON 配置对象(如表单 schema、权限菜单树),运行时只读或整块替换
- 从后端一次性拉取的列表数据,后续仅做筛选、排序等非响应式计算,不修改原数组元素
与 reactive / ref 的典型误用对比
很多人一开始会写成这样:
const list = ref([{ id: 1, name: 'A' }, { id: 2, name: 'B' }]) // ❌ 深层代理,浪费资源
其实真正需要的是引用变化本身:
const list = shallowRef([{ id: 1, name: 'A' }, { id: 2, name: 'B' }]) // ✅ 只响应 list.value = 新数组
此时 list.value[0].name = 'C' 不会触发视图更新——这正是预期行为,不是 bug。
配合 markRaw 提升大型不可变对象性能
shallowRef 常和 markRaw 成对出现,用于彻底绕过响应式系统处理。
- markRaw 标记的对象,即使传入 reactive 或 ref,也不会被代理
- shallowRef 包裹 markRaw 后的对象,既保证了 .value 访问安全,又杜绝了任何响应式开销
示例:
import { shallowRef, markRaw } from 'vue'
// 大型静态配置(可能含函数、循环引用等)
const config = markRaw({
columns: [{ key: 'name', title: '姓名' }],
rules: { name: { required: true } },
renderHeader: (h) => h('span', '自定义标题')
})
const configRef = shallowRef(config)
// 替换整个配置时才更新
function updateConfig(newConf) {
configRef.value = markRaw(newConf)
}
需要局部更新时:triggerRef 是关键补丁
shallowRef 的限制是“改内部不响应”,但业务中偶尔需要批量修改后再统一刷新——这时不用重赋值整个对象,避免 GC 压力。
- 先直接修改 shallowRef.value 的嵌套属性(无响应)
- 调用 triggerRef 强制通知所有依赖该 ref 的 effect 重新执行
- 一次触发,全量更新,比逐条赋值高效得多
场景举例(表格批量设状态):
const tableData = shallowRef([
{ id: 1, status: 'pending' },
{ id: 2, status: 'pending' }
])
function batchSetStatus(status) {
tableData.value.forEach(item => item.status = status)
triggerRef(tableData) // ✅ 主动唤醒依赖,仅一次更新
}
不复杂但容易忽略:shallowRef 的价值不在“写起来多简单”,而在于你清楚知道哪些数据不该响应、哪些更新该合并、哪些对象该彻底豁免。组合式 API 给你模块化封装的能力,把这类判断收敛到自定义 Hook 里,比如 useShallowList 或 useImmutableConfig,才是高性能组件的真正起点。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










