vue3最简单的响应式原理

40 阅读1分钟

最近在学习vue3 记录下

先实现最简单的

let obj = { name: 'jw', age: 30, address: '222' }
const state = reactive(obj);
effect(() => {
    document.getElementById('app').innerHTML = state.age + state.name
})   

reactive的现实

function reactive(target) {
    // 对传进来的做一层proxy代理
  const proxy = new Proxy(target, mutableHandlers);
  return proxy;
}

effect实现

export class ReactiveEffect {
  public active = true;
  public deps = [];
  public parent = undefined;
  constructor(public fn,) {
  }
  run() {
    try {
      this.parent = activeEffect;
      activeEffect = this;
      return this.fn(); // 这个地方做了依赖收集
    } finally {
      activeEffect = this.parent;
      this.parent = undefined;
    }
  }
}
// 依赖收集 就是将当前的effect变成全局的  稍后取值的时候可以拿到这个全局的effect
export function effect(fn) {
  const _effect = new ReactiveEffect(fn);
  _effect.run(); // 默认让响应式的effect执行一次
}

默认会执行 effect一次 执行的话 会有取值的操作 这个时候就会触发依赖的收集

mutableHandlers

export const mutableHandlers = {
  get(target, key, receiver) {
    // 标记这个对象是响应式
    if (ReactiveFlags.IS_REACTIVE == key) {
      return true;
    }
    // 收集依赖
    track(target, key);
    let r = Reflect.get(target, key, receiver); // 处理了this问题

    if (isObject(r)) {
      // 只有用户取值的时候 才会进行二次代理,不用担心性能
      return reactive(r);
    }
    return r;
  },
  set(target, key, value, receiver) {
    // 用户赋值的操作
    let oldValue = target[key]; // 没有修改之前的值

    // set 方法的返回值是一个boolean
    let r = Reflect.set(target, key, value, receiver);

    if (oldValue !== value) {
      trigger(target, key, value, oldValue);
    }
    return r;
  },
};

get的时候 收集依赖 weakMap {obj: map{key: set(effect)}} 这样一个结构 set的时候 触发执行 从这个weakMap中 去除 对应的 effect去执行一次 触发更新

有兴趣的 查看完整源码 gitee.com/FanBingKun/…

自律