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 的实现机制,可以在适当场景下有效提升应用性能,同时避免不必要的响应式开销。

Vue3 的响应式系统源码级 shallowRef 与 shallowReactive 的实现原理与适用场景 描述 shallowRef 和 shallowReactive 是 Vue3 响应式系统中提供的浅层响应式 API。与 ref 和 reactive 的深层响应式不同,它们只对对象的第一层属性进行响应式处理,适用于特定性能优化场景。 实现原理 1. 浅层响应式的设计动机 深层响应式(ref/reactive)会递归转换对象的所有嵌套属性,当处理大型对象或不需要深层响应式的场景时,这会带来不必要的性能开销 浅层响应式通过减少 Proxy 对象的创建和依赖追踪,提升性能并减少内存占用 2. shallowReactive 的实现 3. shallowRef 的实现 4. 与深层响应式的对比 深层响应式(reactive) :对象的所有嵌套层级都是响应式的 浅层响应式(shallowReactive) :只有第一层属性是响应式的 适用场景与最佳实践 1. 性能优化场景 大型列表或表格数据,只需要响应第一层变化 第三方库的集成,避免对不可控对象进行深度响应式转换 频繁更新的数据,减少响应式系统的开销 2. 与深层响应式的组合使用 3. 注意事项 浅层响应式对象需要显式替换才能触发更新 与 watch API 配合时需要明确监视的深度 在模板中使用时要注意数据更新的触发条件 通过理解 shallowRef 和 shallowReactive 的实现机制,可以在适当场景下有效提升应用性能,同时避免不必要的响应式开销。