64 lines
1.7 KiB
JavaScript
64 lines
1.7 KiB
JavaScript
function isObject(obj) {
|
||
return obj !== null && typeof obj === 'object';
|
||
}
|
||
|
||
function reactive(target) {
|
||
if (!isObject(target)) return target;
|
||
const handler = {
|
||
get(target, key, receiver) {
|
||
track(target, key);
|
||
const result = Reflect.get(target, key, receiver);
|
||
return isObject(result) ? reactive(result) : result;
|
||
},
|
||
set(target, key, value, receiver) {
|
||
const oldValue = target[key];
|
||
if (oldValue !== value) {
|
||
const result = Reflect.set(target, key, value, receiver);
|
||
trigger(target, key);
|
||
return result;
|
||
}
|
||
}
|
||
};
|
||
return new Proxy(target, handler);
|
||
}
|
||
|
||
const targetMap = new WeakMap();
|
||
const effectStack = [];
|
||
|
||
function track(target, key) {
|
||
if (effectStack.length) {
|
||
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 Set()));
|
||
dep.add(effectStack[effectStack.length - 1]);
|
||
}
|
||
}
|
||
|
||
function trigger(target, key) {
|
||
const depsMap = targetMap.get(target);
|
||
if (depsMap) {
|
||
const effects = new Set([...(depsMap.get(key) || [])]);
|
||
effects.forEach(effect => effect());
|
||
}
|
||
}
|
||
|
||
function watchEffect(effect) {
|
||
effectStack.push(effect);
|
||
try {
|
||
return effect();
|
||
} finally {
|
||
effectStack.pop();
|
||
}
|
||
}
|
||
|
||
// 使用示例
|
||
const data = reactive({ count: 0 });
|
||
watchEffect(() => {
|
||
console.log(`Count is: ${data.count}`);
|
||
});
|
||
|
||
setTimeout(() => {
|
||
data.count++; // 触发副作用,在控制台打印出新的count值
|
||
}, 1000);
|