ref相关知识点

268 阅读2分钟

ref

ref作用

将传入的数据转为响应式数据,即数据发生改变,视图同步更新

原理

ref源码分析

当声明变量,执行ref函数时,const a = ref(1),ref函数内部调用createRef函数,将传给ref函数的value传给createRef函数

export function ref<T extends object>(
  value: T
): [T] extends [Ref] ? T : Ref<UnwrapRef<T>>
export function ref<T>(value: T): Ref<UnwrapRef<T>>
export function ref<T = any>(): Ref<T | undefined>
export function ref(value?: unknown) {
  return createRef(value, false)
}

createRef

createRef中,对传入的value进行类型判断,如果value是ref对象,则直接返回value,不作任何处理,否则,新建一个RefImpl对象

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

RefImpl

在该函数中可以看到,构造器的第一个参数是传入的值,第二个参数是false(判断是不是shallowRef),通过getter和setter监听value的变化,所以我们赋值的时候,要赋值给xxx.value,

class RefImpl<T> {
  private _value: T
  private _rawValue: T

  public dep?: Dep = undefined
  public readonly __v_isRef = true

  constructor(value: T, public readonly _shallow: boolean) {
    this._rawValue = _shallow ? value : toRaw(value)
    this._value = _shallow ? value : toReactive(value)
  }

  get value() {
    trackRefValue(this)
    return this._value
  }

  set value(newVal) {
    newVal = this._shallow ? newVal : toRaw(newVal)
    if (hasChanged(newVal, this._rawValue)) {
      this._rawValue = newVal
      this._value = this._shallow ? newVal : toReactive(newVal)
      triggerRefValue(this, newVal)
    }
  }
}

toReactive

将传入的值进行响应式监听

export const toReactive = <T extends unknown>(value: T): T =>
  isObject(value) ? reactive(value) : value

isRef

isRef作用

判断某个值是不是ref对象,返回值是true或false

原理

isRef源码分析

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

shallowRef

shallowRef作用

对传入的值的响应式监听只到value这一层,内部不会再调用toReactive函数对value对应的对象做进一步响应式监听

原理

shallowRef源码分析

与ref源码的区别在于第二个参数的值为true

export function shallowRef<T extends object>(
  value: T
): T extends Ref ? T : ShallowRef<T>
export function shallowRef<T>(value: T): ShallowRef<T>
export function shallowRef<T = any>(): ShallowRef<T | undefined>
export function shallowRef(value?: unknown) {
  return createRef(value, true)
}

triggerRef

triggerRef作用

该函数传入一个ref的值,由于对数据的监听深度不够(如shallowRef),ref的值发生了改变,但是有想要页面更新,可以使用triggerRef

原理

triggerRef源码分析

export function triggerRef(ref: Ref) {
  triggerRefValue(ref, __DEV__ ? ref.value : void 0)
}

triggerRefValue源码

export function triggerRefValue(ref: RefBase<any>, newVal?: any) {
  ref = toRaw(ref)
  if (ref.dep) {
    if (__DEV__) {
      triggerEffects(ref.dep, {
        target: ref,
        type: TriggerOpTypes.SET,
        key: 'value',
        newValue: newVal
      })
    } else {
      triggerEffects(ref.dep)
    }
  }
}

triggerEffects源码

export function triggerEffects(
  dep: Dep | ReactiveEffect[],
  debuggerEventExtraInfo?: DebuggerEventExtraInfo
) {
  // spread into array for stabilization
  for (const effect of isArray(dep) ? dep : [...dep]) {
    if (effect !== activeEffect || effect.allowRecurse) {
      if (__DEV__ && effect.onTrigger) {
        effect.onTrigger(extend({ effect }, debuggerEventExtraInfo))
      }
      if (effect.scheduler) {
        effect.scheduler()
      } else {
        effect.run()
      }
    }
  }
}

customRef

customRef作用

自定义自己的ref

使用案例

function myRef(value) {
    return customRef(track, trigger) {
        return {
            get() {
                track()
                return value
            },
            set(newVal) {
                value = newVal
                trigger()
            }
        }
    }
}

原理

customRef源码

export function customRef<T>(factory: CustomRefFactory<T>): Ref<T> {
  return new CustomRefImpl(factory) as any
}

CustomRefImpl源码

class CustomRefImpl<T> {
  public dep?: Dep = undefined

  private readonly _get: ReturnType<CustomRefFactory<T>>['get']
  private readonly _set: ReturnType<CustomRefFactory<T>>['set']

  public readonly __v_isRef = true

  constructor(factory: CustomRefFactory<T>) {
    const { get, set } = factory(
      () => trackRefValue(this),
      () => triggerRefValue(this)
    )
    this._get = get
    this._set = set
  }

  get value() {
    return this._get()
  }

  set value(newVal) {
    this._set(newVal)
  }
}