揭开Vue3的幕后秘密:200行代码实现mini版reactive + effect
2023-01-26 15:29:36
揭秘 Vue3:200行代码中的响应式世界
探索 Reactive 的魔力:数据响应性的关键
在 Vue3 中,Reactive 扮演着数据响应性的魔法师角色。它将普通的数据对象变身为响应式对象,使它们能够在数据发生变化时及时通知视图进行更新。
Reactive 巧妙地对数据对象进行递归遍历,为每个属性套上了一层 getter 和 setter 函数的保护罩。当我们访问数据对象的属性时,getter 函数便会被触发,而当我们修改属性时,setter 函数则会闪亮登场。
Effect:视图的忠实守护者
Effect 函数宛若视图的忠实守护者,时刻监听数据对象的变动,一旦数据发生改变,它便迅速通知视图进行更新。
在创建 Effect 函数时,我们会传入一个回调函数。每当数据对象发生改变时,这个回调函数便会跳出来执行,确保视图与最新数据保持同步。
200行代码的惊人创举
现在,让我们揭开 200 行代码是如何缔造出 Reactive 和 Effect 的传奇。
// Reactive
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
// 触发 getter 函数
const value = Reflect.get(target, key);
// 如果是对象,递归调用 reactive
if (isObject(value)) {
return reactive(value);
}
// 收集依赖
track(target, key);
return value;
},
set(target, key, newValue) {
// 触发 setter 函数
const oldValue = Reflect.get(target, key);
if (newValue !== oldValue) {
// 设置新值
Reflect.set(target, key, newValue);
// 触发 effect 函数
trigger(target, key);
}
return true;
}
});
}
// Effect
function effect(fn) {
const effectObj = {
fn,
deps: new Set()
};
// 执行 effect 函数
effectObj.fn();
// 将 effect 对象添加到 effect 队列
activeEffect = effectObj;
return effectObj;
}
// 依赖收集
function track(target, key) {
if (activeEffect) {
// 将 target 和 key 添加到 effect 对象的 deps 集合中
activeEffect.deps.add(target);
}
}
// 触发 effect 函数
function trigger(target, key) {
// 从 effect 队列中找到依赖了 target 和 key 的 effect 对象
const effects = effectQueue.filter(effectObj => effectObj.deps.has(target));
// 调用 effect 对象的回调函数
effects.forEach(effectObj => effectObj.fn());
}
常见问题解答
1. Reactive 和 Effect 的关系是什么?
Reactive 将数据对象变为响应式,而 Effect 监听数据对象的改变并更新视图。
2. 为什么 Reactive 要使用 Proxy?
Proxy 提供了在不修改原始对象的情况下劫持属性访问和修改操作的能力。
3. Effect 如何知道哪些数据对象发生了改变?
Reactive 通过收集依赖关系来跟踪访问和修改数据对象。当数据对象发生改变时,Reactive 会触发 Effect 函数。
4. Effect 的执行时机是什么?
Effect 在以下情况下执行:
- 创建 Effect 时
- 响应式数据发生改变时
5. 我可以在 Effect 中执行异步操作吗?
是的,你可以在 Effect 中执行异步操作。