console
const data = {
ok: true,
text: "hello",
foo: 1,
};
let activeEffect;
const effectStack = [];
const effect = (fn, options = {}) => {
const effectFn = () => {
cleanup(effectFn);
activeEffect = effectFn;
effectStack.push(activeEffect);
fn();
effectStack.pop();
activeEffect = effectStack[effectStack.length - 1];
};
effectFn.options = options;
effectFn.deps = [];
effectFn();
};
function cleanup(effectFn) {
for (let i = 0; i < effectFn.deps.length; i++) {
const deps = effectFn.deps[i];
deps.delete(effectFn);
}
effectFn.deps.length = 0;
}
const bucket = new WeakMap();
const obj = new Proxy(data, {
get(target, key) {
track(target, key);
return target[key];
},
set(target, key, newVal) {
target[key] = newVal;
trigger(target, key);
},
});
function track(target, key) {
if (!activeEffect) return target[key];
let depsMap = bucket.get(target);
if (!depsMap) {
bucket.set(target, (depsMap = new Map()));
}
let deps = depsMap.get(key);
if (!deps) {
depsMap.set(key, (deps = new Set()));
}
deps.add(activeEffect);
activeEffect.deps.push(deps);
}
function trigger(target, key) {
const depsMap = bucket.get(target);
if (!depsMap) return;
const effects = depsMap.get(key);
const effectsToRun = new Set();
effects &&
effects.forEach((effectFn) => {
if (effectFn !== activeEffect) {
effectsToRun.add(effectFn);
}
});
effectsToRun.forEach((effectFn) => {
if (effectFn.options.scheduler) {
effectFn.options.scheduler(effectFn);
} else {
effectFn();
}
});
}
effect(() => {
console.log("effect run");
obj.foo++;
});
setTimeout(() => {
obj.ok = false;
obj.text = "ha ha ha !!!";
}, 1000);
<div id="test"></div>