2-实现effect && reactive

133 阅读1分钟

新增reactivity目录

image.png

  • test 文件夹放的是单侧文件

实现reactive

reactive.spec.ts

import { reactive } from "../index";

describe("reactive", () => {
  it("it-reactive", () => {
    const initObj = { foo: 1 };
    const reactiveObj = reactive(initObj);
    // initObj 不等于 reactiveObj
    expect(reactiveObj).not.toBe(initObj);
  });
});

index.ts

// 基于Proxy实现一个reactive
export function reactive(raw) {
  return new Proxy(raw, {
    get(target, key, receiver) {
      const res = Reflect.get(target, key, receiver);
      return res;
    },
    set(target, key, value, receiver) {
      const res = Reflect.set(target, key, value, receiver);
      return res;
    },
  });
}

进行reactive单侧

yarn test reactive

image.png

实现effect

effect.spec.ts

  /** 实现effect侦听
   * 1. effect初始化会直接调用
   * 2. reactive包裹的参数发生变动,effect会再次执行
   */
  it("effect", () => {
    const user = reactive({
      age: 10,
    });
    let nextAge;
    effect(() => {
      nextAge = user.age + 1;
    });
    expect(nextAge).toBe(11);
    // update
    user.age++;
    expect(nextAge).toBe(12);
  });

effect.ts

// 当前活跃的effect实例
+ let activeEffect;
class Effect {
  private _fn: any;

  constructor(fn) {
    this._fn = fn;
  }

  // 执行effect接收的fn
  run() {
    activeEffect = this;
    this._fn();
  }
}

// 收集依赖
+ const targetMap = new Map(); // 所有的依赖,触发依赖的时候会从这里面取
+ export function track(target, key) {
+   let depMap = targetMap.get(target);
+   if (!depMap) {
+     depMap = new Map();
+     targetMap.set(target, depMap);
+   }
+   let dep = depMap.get(key);
+   if (!dep) {
+     dep = new Set();
+     depMap.set(key, dep);
+   }
+   dep.add(activeEffect);
+ }

// 触发依赖
+ export function trigger(target, key) {
+   let depMap = targetMap.get(target);
+   let dep = depMap.get(key);
+   for (const effect of dep) {
+     effect.run();
+   }
+ }

export function effect(fn) {
  const _effect = new Effect(fn);
  _effect.run();
}

index.ts

export function reactive(raw) {
  return new Proxy(raw, {
    get(target, key) {
      const res = Reflect.get(target, key);
      // 收集依赖
      track(target, key);
      return res;
    },
    set(target, key, value) {
      const res = Reflect.set(target, key, value);
      // 触发依赖
      trigger(target, key);
      return res;
    },
  });
}

执行单侧

yarn test effect

image.png