10-实现 isRef & unRef

309 阅读1分钟

思考功能

  1. isRef用来判断对象是否为ref对象
  2. unRef帮助提取ref对象的值

根据单侧实现功能

ref.spec.ts

 /** 看得见的思考
   * 1. 给ref实例一个固定标识
   * 2. 如果能取到该标识证明就是ref对象
   */
  it("isRef", () => {
    const a = ref(1);
    const user = reactive({
      age: 1,
    });
    expect(isRef(a)).toBe(true);
    expect(isRef(1)).toBe(false);
    expect(isRef(user)).toBe(false);
  });

  /** 看得见的思考
   * 1. 可以利用isRef判断
   * 2. 如果是ref对象,则返回ref.value,否则直接返回原值
   */
  it("unRef", () => {
    const a = ref(1);
    expect(unRef(a)).toBe(1);
    expect(unRef(1)).toBe(1);
  });

实现 isRef

/*
 * @Author: Lin zefan
 * @Date: 2022-03-17 18:23:36
 * @LastEditTime: 2022-03-20 15:11:23
 * @LastEditors: Lin zefan
 * @Description: ref
 * @FilePath: \mini-vue3\src\reactivity\ref.ts
 *
 */
import { reactive } from ".";
import { isObject, hasChanged } from "../shared";
import { isTracking, trackEffect, triggerEffect } from "./effect";

class RefImpl {
  _dep: any;
  private _value: any;
+  // ref对象标识
+  __v_isRef = true;

  constructor(value) {
    /**
     * 1. 需要判断value是基本类型还是引用类型
     * 2. 引用类型需要用reactive包裹,做到深度侦听
     */
    this._value = convert(value);
    this._dep = new Set();
  }

  get value() {
    /** 思考
     * 1. get要收集依赖
     */
    isTracking() && trackEffect(this._dep);
    return this._value;
  }

  set value(newVal) {
    /** 思考
     * 1. 先判断新老值,值不相等再做更新
     * 2. 更新ref.value
     * 3. 更新依赖的值
     */
    if (hasChanged(this._value, newVal)) return;
    this._value = convert(newVal);
    triggerEffect(this._dep);
  }
}

function convert(value) {
  return isObject(value) ? reactive(value) : value;
}

export function ref(ref) {
  return new RefImpl(ref);
}

+ export function isRef(ref) {
+   return !!ref.__v_isRef;
+ }

实现 unRef

/*
 * @Author: Lin zefan
 * @Date: 2022-03-17 18:23:36
 * @LastEditTime: 2022-03-21 23:28:20
 * @LastEditors: Lin zefan
 * @Description: ref
 * @FilePath: \mini-vue3\src\reactivity\ref.ts
 *
 */

export function unRef(ref) {
  return isRef(ref) ? ref.value : ref;
}