You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
64 lines
1.7 KiB
64 lines
1.7 KiB
4 months ago
|
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);
|