Vue 3.x Refs

703 阅读2分钟

Refs API的原理

ref

接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象具有指向内部值的单个 property .value

const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

ref 与 reactive 最大的区别在于,reactive的参数只能是对象,但 ref 可以是任意类型

ref对象属性

ref的参数如果是一个对象的话,会转换为 reactive ,reactive 会进行深度转换把所有对象元素都转换为reactive。

    const a = ref({});
    console.log(isReactive(a.value)); // true
    
    const b = ref({ c : {} });
    console.log(isReactive(b.value.c)); // true

ref初始化

const a = ref(1);

/**
 * @param {any} ref实参 1
 * @param {Boolean} 对象元素是否转为 reactive false
 */
function ref(value?: unknown) {
  return createRef(value)
}

function createRef(rawValue: unknown, shallow = false) {
  if (isRef(rawValue)) {
    return rawValue
  }
  // rawValue:1
  // shallow:false 
  return new RefImpl(rawValue, shallow)
}

shallowRef

创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的。

不想要深度响应式的 reactive 就可以使用 shallowRef

const a = ref({})
isReactive(a.value) // true

const b = shallowRef({})
isReactive(b.value) // false
const a = shallowRef(1);

function shallowRef(value?: unknown) {
  return createRef(value, true)
}

function createRef(rawValue: unknown, shallow = false) {
  if (isRef(rawValue)) {
    return rawValue
  }
  // rawValue:1
  // shallow:true 
  return new RefImpl(rawValue, shallow)
}

RefImpl

class RefImpl<T> {
  
  私有变量 _value用来保存传入参数
  private _value: T

  公用只读变量 __v_isRef标记对象为 ref
  public readonly __v_isRef = true

  constructor(private _rawValue: T, public readonly _shallow = false) {
    // 如果_rawValue是对象,将其转为 reactive 响应式对象。它的所有对象元素都会转化为 reactive 响应式对象
    // shallowRef就不会将元素转化为 reactive 响应式对象。
    this._value = _shallow ? _rawValue : isObject(_rawValue) ? reactive(_rawValue) : _rawValue
  }

  // get value时收集依赖
  get value() {
    track(toRaw(this), TrackOpTypes.GET, 'value')
    return this._value
  }

  // get value时收集依赖
  set value(newVal) {
    // newVal不为_rawValue时,修改value
    if (hasChanged(toRaw(newVal), this._rawValue)) {
      // _rawValue 和 _value 的区别在于
      // _value 保存的可能是转化的 reactive 响应式对象
      // _rawValue 保存的是实参数据
      this._rawValue = newVal
      this._value = this._shallow ? newVal : isObject(newVal) ? reactive(newVal) : newVal
      trigger(toRaw(this), TriggerOpTypes.SET, 'value', newVal)
    }
  }
}
const count = ref({ a: 1 })

710998BE-B4B9-42EF-9659-4A65463D34DE.png

ref 返回的就是一个对象。ref 与 shallowRef 的区别在于 对象属性 是否转为 reactive 响应式对象

isRef

检查值是否为一个 ref 对象。

function isRef(r: any): r is Ref {
  return Boolean(r && r.__v_isRef === true)
}

判断 __v_isRef 属性是不是true就行。如果你 let a = { __v_isRef : true },也是可以过isRef的。

unref

如果参数是一个 ref,则返回内部值,否则返回参数本身。

function unref<T>(ref: T | Ref<T>): T {
  return isRef(ref) ? ref.value : ref
}
let a = { __v_isRef: true, value: 1111 };

console.log(isRef(a)) => true
console.log(unref(a)) => 111

toRef

可以用来为源响应式对象上的某个 property 新创建一个 ref。然后,ref 可以被传递,它会保持对其源 property 的响应式连接。

function toRef(object,key){
  // 如果已经是一个ref,直接返回
  return isRef(object[key])
    ? object[key]
    : (new ObjectRefImpl(object, key) as any)
}

ObjectRefImpl

class ObjectRefImpl<T extends object, K extends keyof T> {

public readonly __v_isRef = true

constructor(private readonly _object: T, private readonly _key: K) {}

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

  set value(newVal) {
    this._object[this._key] = newVal
  }
}
const a = reactive({ foo: 1, bar: 2 }) 

const b = toRef(state, 'foo') 

b.value = 2
// this._object[this._key] = newVal
// a[foo] = 2
console.log(a.foo) // 2 

a.foo = 3
console.log(b.value) // 3
// return this._object[this._key]
// return a[foo]

简简单单就是个代理

toRefs

function toRefs(object){
  const ret: any = isArray(object) ? new Array(object.length) : {}

  for (const key in object) {
    ret[key] = toRef(object, key)
  }

  return ret

}

遍历一遍,用toRef