Q16
★ ★ ★ ★ ★
Vue 3 中的 shallowReactive 和 shallowRef 有何用途?
⚡ 速记答案(30 秒)
两者都只对"第一层"做响应式,内部嵌套对象原样保留为非响应式。适用场景:大对象/大数组、第三方实例等,减轻性能和行为上的风险。
📖 详细讲解
标准面试回答(推荐记住)
shallowReactive 只代理对象的第一层属性,嵌套对象不会被转为响应式;shallowRef 同理,只追踪 .value 的变化。适用于大型对象、第三方库实例等不需要或不能深度代理的场景,可以避免不必要的性能开销。
性能优化:Shallow API
默认的 reactive 和 ref 是深度的。当有一个巨大的嵌套对象(例如:图表库的大型配置对象、从服务端获取的只读大列表)时,深度递归代理会带来巨大的性能开销。
shallowReactive:
- 只有根级别的属性是响应式的。
- 读取嵌套属性不会触发 getter 代理,不会递归转为 Proxy。
- 赋值嵌套属性不会触发 setter 更新。
shallowRef:
- 只有
.value的再次赋值是响应式的。 - 修改
.value内部对象的属性不会触发更新。 - 常用于
shallowRef(someBigObject),当需要更新时,直接替换整个对象ref.value = newBigObject,或者配合triggerRef(ref)手动触发。
场景:
- 集成第三方库(ECharts 实例、Three.js 对象)
- 不可变数据结构
- 防抖/节流的中间状态
✅ 面试要点
- •理解浅层响应式的含义
- •知道适用场景
- •了解 triggerRef 的用途
💻 代码示例
shallow 系列用法
import { shallowReactive, shallowRef, triggerRef } from 'vue'
// shallowReactive - 只代理第一层
const state = shallowReactive({
count: 0,
nested: { value: 1 } // 不是响应式的!
})
state.count++ // ✅ 触发更新
state.nested.value++ // ❌ 不会触发更新
state.nested = { value: 2 } // ✅ 触发更新
// shallowRef - 只追踪 .value 的替换
const data = shallowRef({ items: [] })
data.value.items.push(1) // ❌ 不会触发更新
data.value = { items: [1] } // ✅ 触发更新
// 强制触发更新
triggerRef(data)