watchEffect 的核心价值在于“写什么,就监听什么”——自动追踪回调中实际读取的响应式数据并立即执行,支持 flush 调度、异步清理和手动停止。

watchEffect 的核心价值在于“写什么,就监听什么”——你只需把副作用逻辑放进回调函数里,Vue 会自动识别其中读取的响应式数据(如 ref.value、reactive 对象属性),建立依赖关系,并在首次渲染时立刻执行一次,后续只要这些数据变化,函数就重跑。
自动收集依赖的关键规则
它不靠声明,而靠执行时的“访问行为”来追踪:
- 函数体中实际读取了
count.value和user.name,就只追踪这两个;没读到的字段,哪怕在同一对象里,也不会响应变化 - 条件分支会影响依赖:比如
if (show) { state.msg },只有show为真时,state.msg才被纳入依赖 - 对 reactive 对象是浅层追踪:修改
user.profile.age能触发,但直接替换整个user对象才真正更新依赖链 -
异步代码里读取的值不会被追踪:
await fetch(...); console.log(data.value)中的data.value不在初始 track 阶段,变化不会触发重跑
立即执行与副作用控制
它默认一创建就运行,适合初始化同步逻辑,但也需注意时机管理:
- 用
flush: 'post'延迟到 DOM 更新后执行,方便操作真实节点(如获取元素尺寸、聚焦输入框) - 用
flush: 'pre'(默认)在组件更新前运行,适合提前计算或拦截状态 - 避免在函数开头就
await长时间 pending 的 Promise,否则会阻塞后续响应
清理未完成的异步操作
多次快速变化容易引发竞态,必须主动清理上一轮未结束的副作用:
- 传入的
onInvalidate回调会在下一次执行前或组件卸载时自动调用 - 常见做法:用
AbortController中断请求,或用标志位判断响应是否过期 - 定时器、事件监听器、WebSocket 连接等资源,都应在此处释放
手动停止监听的场景
watchEffect 返回一个 stop() 函数,不是可有可无的细节:
- 组件卸载前调用,防止内存泄漏(尤其搭配异步时)
- 满足业务条件时主动停掉,比如用户离开某页面、搜索框清空后不再监听关键词
- 停止后回调彻底失效,即使依赖再变也不会执行


















