Skip to content

添加反向依赖 ​

本节目标:理解“添加反向依赖”的核心思路,并能把它用于实际开发或面试表达。 单向是指属性记录了Effect; 反向是指让effect也记录了它被哪些属性收集过; 这样做的好处是为了可以清理;

使用反向依赖的例子:
effect(() => {
  flag ? this.name : this.age
})
flag为true时,name收集了effect;
flag为false时,age收集了effect;此时,我们要把name收集的effect清空,这时要通过effect将所有的记录都删掉,再把age的加进去;
export let activeEffect = undefined;
// 拥有一个run方法,就是执行effect
class ReactiveEffect {
  ==public== ==deps== ===== ==[];==
  public parent = null;
  // 创建的effect默认是激活的
  public active = true
  // public修饰符会在实例上添加这个参数作为属性
  // 相当于this.fn=fn
  constructor(public fn) { }
  run() {
    // 如果是非激活的,只需要执行函数,不需要进行依赖收集
    if (!this.active) {
      this.fn();
    }
    try {
      // 第一个实例的parent是undefined
      this.parent = activeEffect;
      activeEffect = this;
      return this.fn();
    } finally {
      // 代码执行完后,
      // 一、重置activeEffect,指向parent
      activeEffect = this.parent;
      // 二、重置parent指针,undefined?
      this.parent = null;
    }
  }
}
export const effect = (fn) => {
  // 这里的fn可以根据数据变化,重新执行;
  // effect可以嵌套着写
  // 创建响应式的effect
  const _effect = new ReactiveEffect(fn);
  // 默认先执行一次
  _effect.run();
}
const targetMap = new WeakMap();
export function track(target, type, key) {
  // 如果不是在effect中获取属性,是不跟踪的;
  if (!activeEffect) return;
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    // 将源对象与一个map关联起来;
    // 这个map的键是属性名,值是一个set,set中放置的是effect实例
    // 当map中的属性变化时,我们把对应的set中的effect实例拿出来,调用其run方法;
    // 从而又执行了一次effect的fn函数;
    targetMap.set(target, (depsMap = new Map()));
  }
  // 再到这个depsMap中查找当前属性对应的Set;
  let dep = depsMap.get(key);
  if (!dep) {
    depsMap.set(key, (dep = new Set()));
  }
  // 看set中是否存在当前的effect
  let shouldTrack = !dep.has(activeEffect);
  if (shouldTrack) {
    dep.add(activeEffect);
    // effect实例deps属性是一个数组,里面存在着set,set中存放着属性依赖的effect;
    // 稍后清理的时候会用到;
    // 如果effect用到了两个属性,deps数组就会有两个成员set;
    ==activeEffect====.====deps====.====push====(====dep====);==
  }
}

本站总访问 — 次