测试
import { effect } from "./effect.mjs";
import { reactive } from "./reactive.mjs";
const obj = { a: 1, b: 2 };
const proxyObj = reactive(obj);
effect(() => {
console.log("obj.a", proxyObj.a);
});
effect(() => {
console.log("obj.b", proxyObj.b);
});
proxyObj.a = 2;
打印结果
obj.a 1
obj.b 2
obj.a 2
reactive
基于 proxy 在 get set 方法中收集和触发依赖
// reactive.mjs
import { track, trigger } from "./dep.mjs";
const reactiveMap = new WeakMap();
export function reactive(target) {
const res = new Proxy(target, {
get(target, key) {
track(target, key);
return Reflect.get(target, key);
},
set(target, key, value) {
const result = Reflect.set(target, key, value);
trigger(target, key);
return result;
},
});
reactiveMap.set(target, res);
return res;
}
dep
维护 obj 和 执行函数的依赖关系
// dep.mjs
import { activeSub } from "./effect.mjs";
const targetMap = new WeakMap();
class Dep {
map;
key;
constructor() {}
track() {
// 当前正在执行的函数
this.sub = activeSub;
}
trigger() {
this.sub.notify();
}
}
// 收集依赖
export function track(target, key) {
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Dep()));
dep.map = depsMap;
dep.key = key;
}
dep.track();
}
// 触发依赖
export function trigger(target, key) {
let depsMap = targetMap.get(target);
const dep = depsMap.get(key);
dep.trigger();
}
effect
// effect.mjs
export let activeSub;
class ReactiveEffect {
constructor(fn) {
this.fn = fn;
}
run() {
activeSub = this;
this.fn();
}
notify() {
this.fn();
}
}
export function effect(fn) {
const e = new ReactiveEffect(fn);
e.run();
return e.run.bind(e);
}