在 Vue 3 的响应式系统中,effect 函数是核心机制之一,它的作用是创建一个响应式副作用(Reactive Effect),能够自动追踪依赖的响应式数据,并在这些数据变化时重新执行对应的副作用逻辑。它是 Vue 3 实现数据驱动视图更新的底层基础。
一、effect 的核心作用
-
依赖追踪(Dependency Tracking)
当你在effect中访问响应式对象(如ref、reactive)时,Vue 会自动记录这些依赖关系。
例如:import { effect, reactive } from 'vue'; const state = reactive({ count: 0 }); effect(() => { console.log('Count changed:', state.count); // 自动追踪 state.count 的依赖 }); -
响应式触发(Reactive Trigger)
当依赖的响应式数据发生变化时,effect会自动重新执行其回调函数:state.count++; // 触发 effect 重新执行,输出 "Count changed: 1"
二、effect 的应用场景
1. 组件渲染(Component Rendering)
Vue 组件的渲染函数本质上被包裹在一个 effect 中。当组件依赖的响应式数据变化时,effect 会触发重新渲染:
// 伪代码示例
const componentUpdateEffect = effect(() => {
renderComponent(); // 渲染逻辑
});
2. 计算属性(Computed Properties)
计算属性的实现基于 effect,通过缓存结果并在依赖变化时重新计算:
const count = ref(0);
const doubled = computed(() => count.value * 2);
// computed 内部通过 effect 追踪 count.value 的变化
3. 侦听器(Watch API)
watch 和 watchEffect 底层依赖 effect 实现依赖追踪和回调触发:
watchEffect(() => {
console.log('WatchEffect triggered:', state.count);
});
4. 自定义响应式逻辑
开发者可以直接使用 effect 实现高级响应式逻辑:
// 当窗口大小变化时,自动更新响应式数据
const windowSize = reactive({ width: 0, height: 0 });
effect(() => {
const updateSize = () => {
windowSize.width = window.innerWidth;
windowSize.height = window.innerHeight;
};
window.addEventListener('resize', updateSize);
// 清理副作用(重要!)
return () => window.removeEventListener('resize', updateSize);
});
三、effect 的关键特性
| 特性 | 说明 |
|---|---|
| 自动依赖追踪 | 只有在回调中实际使用的响应式属性会被追踪为依赖。 |
| 异步调度 | 默认情况下,副作用会在响应式数据变化后异步执行(避免重复触发)。 |
| 清理机制 | 可通过返回一个函数清理副作用(如取消事件监听)。 |
| 手动控制 | 可通过 stop 方法停止响应式副作用的执行。 |
四、使用示例
1. 基本用法
import { effect, ref } from 'vue';
const count = ref(0);
// 创建 effect
const stop = effect(() => {
console.log('Current count:', count.value);
});
count.value = 1; // 输出 "Current count: 1"
// 手动停止 effect
stop();
count.value = 2; // 不再触发输出
2. 清理副作用
effect((onCleanup) => {
const timer = setInterval(() => {
console.log('Running...');
}, 1000);
onCleanup(() => {
clearInterval(timer); // 清理定时器
});
});
五、注意事项
-
避免无限循环
在effect中修改依赖的响应式数据可能导致无限循环:effect(() => { state.count++; // 错误:每次执行都会触发自身重新执行! }); -
性能优化
对于高频更新的数据(如滚动事件),可使用effectScope或手动控制触发频率。 -
与 React 的对比
Vue 的effect类似于 React 的useEffect,但依赖追踪是自动的,无需显式声明依赖数组。
六、底层原理
Vue 3 的响应式系统通过 Proxy 拦截对象的读写操作,结合 effect 的依赖追踪和触发机制,实现了高效的数据驱动更新。当一个 effect 执行时:
- 触发响应式数据的
get操作,将当前effect注册为依赖。 - 响应式数据变化时,触发
set操作,通知所有关联的effect重新执行。
总结
effect 是 Vue 3 响应式系统的核心,用于建立数据与副作用之间的动态绑定。理解它的机制,能帮助你更好地使用 Vue 的高级功能(如自定义响应式逻辑),或在需要时直接操作底层 API。