学习vue3源码 - ref toRef toRefs

52 阅读1分钟

ref的作用

主要是由于proxy代理的是引用数据类型,而不能代理基本数据类型,而一些基本数据类型也需要进行响应式操作,从而引入了ref来做基本数据类型的响应式

思路:

创建一个ref的对象用于包装基本数据类型,通过一个内部的 value 属性来存储原始值,主要也是在get的时候进行依赖收集(可看reactive effect);在set的时候进行找到对应的effect副作用函数,触发更新

示例

class RefImpl {
  public __v_isRef = true // ref标识

  public _value // 用来保存ref的值
  public dep //收集对应的effect
  constructor(public rawValue) {
    this._value = toReactive(rawValue)
  }

  get value() {
    trackRefValue(this)//依赖收集
    return this._value
  }

  set value(newValue) {
    if (newValue !== this.rawValue) {
      this.rawValue = newValue
      this._value = newValue
      triggerRefValue(this)//触发更新
    }
  }
}

toRef toRefs作用

将reactive中的属性直接结构出来会导致该属性丧失响应式,toRef就是将该属性转化为ref,使得该变量依然保持响应性,toRefs的作用则是批量进行上述此操作。

  • toRef: 用于将 reactive 对象中的某个属性转换为一个 ref,包装成一个响应式对象,从而单独解构出来后依然能保持响应性。
  • toRefs: 则是对 toRef 的批量封装,对对象中的每个属性都进行上述转换,确保对象整体在解构后每个属性都能独立地响应变化。

示例

export function toRef(object, key) {
  return new ObjectRefImpl(object, key)
}

class ObjectRefImpl {
  public __v_isRef = true

  constructor(public _object, public _key) {
  }

  get value() {
    return this._object[this._key]
  }

  set value(newValue) {
    this._object[this._key] = newValue
  }
}

export function toRefs(object) {
  const result = {}
  for (const key in object) {
    result[key] = toRef(object, key)
  }
  return result
}

补充

  • 使用 toRef 解构后的值进行修改,其本质上就是直接修改了 reactive 对象中对应的属性