Vue3 的响应式系统源码级 shallowRef 与 shallowReactive 的实现原理与适用场景
字数 670 2025-11-18 15:43:19
Vue3 的响应式系统源码级 shallowRef 与 shallowReactive 的实现原理与适用场景
描述
shallowRef 和 shallowReactive 是 Vue3 响应式系统中提供的浅层响应式 API。与 ref 和 reactive 的深层响应式不同,它们只对对象的第一层属性进行响应式处理,适用于特定性能优化场景。
实现原理
1. 浅层响应式的设计动机
- 深层响应式(ref/reactive)会递归转换对象的所有嵌套属性,当处理大型对象或不需要深层响应式的场景时,这会带来不必要的性能开销
- 浅层响应式通过减少 Proxy 对象的创建和依赖追踪,提升性能并减少内存占用
2. shallowReactive 的实现
function shallowReactive(target) {
// 只对目标对象本身创建响应式,不递归处理嵌套属性
return createReactiveObject(
target,
false, // isReadonly = false
shallowReactiveHandlers, // 浅层处理器
shallowCollectionHandlers
)
}
const shallowReactiveHandlers = {
get: createGetter(false, true), // shallow = true
set,
deleteProperty,
has,
ownKeys
}
function createGetter(isReadonly = false, shallow = false) {
return function get(target, key, receiver) {
// 获取原始值
const res = Reflect.get(target, key, receiver)
// 如果是浅层响应式,直接返回值,不进行深层响应式转换
if (shallow) {
return res
}
// 深层响应式会在这里递归转换嵌套对象
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res)
}
return res
}
}
3. shallowRef 的实现
function shallowRef(value) {
return createRef(value, true) // shallow = true
}
function createRef(rawValue, shallow = false) {
class RefImpl {
constructor(value) {
this._value = shallow ? value : convert(value) // 浅层ref不进行转换
this.__v_isRef = true
this._shallow = shallow
}
get value() {
track(this, 'value') // 依赖收集
return this._value
}
set value(newVal) {
if (hasChanged(newVal, this._rawValue)) {
this._value = this._shallow ? newVal : convert(newVal)
trigger(this, 'value') // 触发更新
}
}
}
return new RefImpl(rawValue)
}
4. 与深层响应式的对比
- 深层响应式(reactive):对象的所有嵌套层级都是响应式的
const deep = reactive({
nested: { value: 1 }
})
// 修改 nested.value 会触发更新
deep.nested.value = 2 // ✅ 触发响应
- 浅层响应式(shallowReactive):只有第一层属性是响应式的
const shallow = shallowReactive({
nested: { value: 1 }
})
// 修改第一层属性会触发更新
shallow.newProp = 'value' // ✅ 触发响应
// 修改嵌套属性不会触发更新
shallow.nested.value = 2 // ❌ 不触发响应
适用场景与最佳实践
1. 性能优化场景
- 大型列表或表格数据,只需要响应第一层变化
- 第三方库的集成,避免对不可控对象进行深度响应式转换
- 频繁更新的数据,减少响应式系统的开销
2. 与深层响应式的组合使用
const state = shallowReactive({
// 浅层响应:只追踪 config 引用变化
config: { theme: 'dark', size: 'large' },
// 深层响应:需要单独包装
user: reactive({
profile: { name: 'John', age: 25 }
})
})
// 修改 config 的属性不会触发更新
state.config.theme = 'light' // ❌ 不触发
// 替换整个 config 会触发更新
state.config = { theme: 'light' } // ✅ 触发
// user 对象保持深层响应
state.user.profile.name = 'Jane' // ✅ 触发
3. 注意事项
- 浅层响应式对象需要显式替换才能触发更新
- 与 watch API 配合时需要明确监视的深度
- 在模板中使用时要注意数据更新的触发条件
通过理解 shallowRef 和 shallowReactive 的实现机制,可以在适当场景下有效提升应用性能,同时避免不必要的响应式开销。