Contents
Tags

一、toRef() 可以灵活地将各种输入转换为 ref,并且根据输入类型提供不同的行为

  • 基本使用
1// Return the existing ref as is
2toRef(existingRef)
3
4// Create a read-only ref that will be called when .value is accessed.
5toRef(() => props.foo)
6
7// Create a normal ref from a non-function value. Equivalent to ref(1).
8toRef(1)
9
10// Convert reactive object properties
11const state = reactive({
12  foo: 1, bar: 2
13  bar: 2
14})
15
16const fooRef = toRef(state, ‘foo’)

 

  • 实现原理 (packages/reactivity/src/ref.ts)

isRef(source): 如果输入本身就是一个 ref,则直接返回它。这种情况通常用于防止重复创建 ref

else: 其他情况,如果输入是普通值,直接调用 ref 函数将其转换为一个 ref

1export function toRef(
2  source: Record<string, any> | MaybeRef,
3  key?: string,
4  defaultValue?: unknown,
5): Ref {
6  if (isRef(source)) {
7    return source
8  } else if (isFunction(source)) {
9    return new GetterRefImpl(source) as any
10  } else if (isObject(source) && arguments.length > 1) {
11    return propertyToRef(source, key!, defaultValue)
12  } else {
13    return ref(source)
14  }
15}

 

isFunction(source): 如果输入是一个函数,返回一个新的 GetterRefImpl 实例

这个 ref 是只读的,它的 value 属性会在每次访问时执行该函数并返回结果

1class GetterRefImpl<T> {
2  public readonly __v_isRef = true
3  public readonly __v_isReadonly = true
4  constructor(private readonly _getter: () => T) {}
5  get value() {
6    return this._getter()
7  }
8}

 

isObject(source) && arguments.length > 1: 如果输入是一个对象并且提供了 key,则通过 propertyToRef 创建一个与对象属性关联的 ref

ObjectRefImpl 用于将对象的某个属性封装成一个 ref。它提供了 getter 和 setter 方法,使得 ref 的 value 属性能够与对象的属性保持同步

1function propertyToRef(
2  source: Record<string, any>,
3  key: string,
4  defaultValue?: unknown,
5) {
6  const val = source[key]
7  return isRef(val)
8    ? val
9    : (new ObjectRefImpl(source, key, defaultValue) as any)
10}
11
12class ObjectRefImpl<T extends object, K extends keyof T> {
13  public readonly __v_isRef = true
14
15  constructor(
16    private readonly _object: T,
17    private readonly _key: K,
18    private readonly _defaultValue?: T[K],
19  ) {}
20
21  get value() {
22    const val = this._object[this._key]
23    return val === undefined ? this._defaultValue! : val
24  }
25
26  set value(newVal) {
27    this._object[this._key] = newVal
28  }
29
30  get dep(): Dep | undefined {
31    /// ...
32  }
33}

 

二、其他

学习的记录,仅供参考