vue3.x源码学习 Ref 学习笔记1

ref

ref最重要的作用,其实是提供了一套Ref类型,什么是ref类型呢?

ref类型

export interface Ref<T = any> {
  value: T
  /**
   * Type differentiator only.
   * We need this to be in public d.ts but don't want it to show up in IDE
   * autocomplete, so we use a private Symbol instead.
   */
   // 用此唯一key,来做Ref接口的一个描述符,让isRef函数做类型判断 [RefSymbol]: true /** * @internal */ _shallow?: boolean } 

对于基本数据类型,函数传递或者对象解构时,会丢失原始数据的引用,换言之,我们没法让基本数据类型,或者解构后的变量(如果它的值也是基本数据类型的话),成为响应式的数据。

// 我们是永远没办法让`a`或`x`这样的基本数据成为响应式的数据的,Proxy也无法劫持基本数据。 const a = 1; const { x: 1 } = { x: 1 } 

但是有时候,我们确实就是想一个数字、一个字符串是响应式的,或者就是想利用解构的写法。那怎么办呢?只能通过创建一个对象,也即是源码中的Ref数据,然后将原始数据保存在Ref的属性value当中,再将它的引用返回给使用者。既然是我们自己创造出来的对象,也就没必要使用Proxy再做代理了,直接劫持这个value的get/set即可,这就是ref函数与Ref类型的由来。

isRef判断

如何判断是否是ref类型,下面是源代码,还是很简单的。

//判断是否是Ref
export function isRef<T>(r: Ref<T> | unknown): r is Ref<T>
export function isRef(r: any): r is Ref {
  return Boolean(r && r.__v_isRef === true)
}

创建Ref

那么是怎么创建ref呢?下面我们就讲讲创建ref。

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

RefImpl构造函数

这里也定义了get/set,没有任何Proxy相关的操作。

class RefImpl<T> {
  private _value: T

  public readonly __v_isRef = true constructor(private _rawValue: T, public readonly _shallow = false) { // 如果是对象就value就是reactive(val),否则就是自己 this._value = _shallow ? _rawValue : convert(_rawValue) } // 获取数据 get value() { // 监听函数收集依赖的方法 track(toRaw(this), TrackOpTypes.GET, 'value') return this._value } // 设置新的值 set value(newVal) { if (hasChanged(toRaw(newVal), this._rawValue)) { this._rawValue = newVal this._value = this._shallow ? newVal : convert(newVal) trigger(toRaw(this), TriggerOpTypes.SET, 'value', newVal) } } } 

convert源码

const convert = <T extends unknown>(val: T): T => isObject(val) ? reactive(val) : val 

这里引入了reactive,如果是对象就value就是reactive(val),否则就是自己,reactive暂时先不讲,放后面讲

toRef&toRefs

toRef也是创建get/set进行拦截,toRefs就是对数组或者对象的属性进行递归设置get/set。

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
  }
}

export function toRef<T extends object, K extends keyof T>(
  object: T,
  key: K
): ToRef<T[K]> {
  return isRef(object[key])
    ? object[key]
    : (new ObjectRefImpl(object, key) as any)
}

export function toRefs<T extends object>(object: T): ToRefs<T> {
  if (__DEV__ && !isProxy(object)) {
    console.warn(`toRefs() expects a reactive object but received a plain one.`)
  }
  const ret: any = isArray(object) ? new Array(object.length) : {}
  for (const key in object) {
    ret[key] = toRef(object, key)
  }
  return ret
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值