watchEffect是Vue组合式API中轻量直观的响应式副作用监听方式,自动追踪回调内读取的响应式数据并立即执行,支持flush配置、onInvalidate清理及手动stop,适用于同步派生状态和需清理的异步场景。

在组合式 API 中,watchEffect 是最轻量、最直观的响应式副作用监听方式——它不需声明监听目标,只要在回调里读取了响应式数据(比如 count.value 或 user.name),Vue 就会自动建立依赖关系,数据一变,函数立刻重跑。
基础用法:写进去就生效
watchEffect 会在定义时立即执行一次,完成初始依赖收集。之后只要它内部访问过的响应式值发生变化,就会重新运行整个函数。
- 直接读取 ref:
watchEffect(() => console.log('当前计数:', count.value)) - 读取 reactive 对象属性:
watchEffect(() => document.title = `用户:${user.name}(${user.age}岁)`) - 支持条件逻辑,未命中分支的响应式变量不会被追踪(例如
if (show) console.log(msg.value),当show为 false 时,msg的变化不会触发重跑)
控制执行时机与清理副作用
实际开发中常需避免重复请求、内存泄漏或 DOM 操作时机错乱,watchEffect 提供了关键配置:
- 用
flush: 'post'延迟到 DOM 更新后执行,适合需要操作真实节点的场景:watchEffect(() => { inputRef.value?.focus(); }, { flush: 'post' }) - 用
onInvalidate清理上一轮未完成的异步操作(如取消 pending 请求、清除定时器):watchEffect((onInvalidate) => { const timer = setTimeout(() => ..., 500); onInvalidate(() => clearTimeout(timer)); }) - 调用返回的
stop()函数可手动停止监听,组件卸载前务必调用(尤其搭配异步逻辑时):const stop = watchEffect(() => {...}); onUnmounted(stop);
注意这些常见陷阱
watchEffect 的“自动”很省心,但也容易忽略细节:
-
异步代码里的响应式读取不被追踪:await 后面的
data.value不在初始 track 阶段,修改它不会触发重跑 - 不提供新旧值参数:只重跑整个函数,无法像 watch 那样对比变化前后;如需差异判断,应改用 watch
-
对 reactive 是浅层追踪:修改
obj.count会触发,但若执行obj = { count: 5 }(替换整个对象),才真正触发依赖更新 -
默认立即执行:和 watch 的惰性不同,首次渲染即运行,若只想在变化后执行,需配合逻辑判断或改用 watch +
immediate: false
什么时候优先选 watchEffect?
当你关注的是“只要这几个响应式值一动,我就重新做这件事”,且依赖关系动态、嵌套深、或难以提前枚举时,watchEffect 更自然:
- 同步更新派生状态(如计算 document.title、class 列表)
- 触发带清理需求的异步副作用(搜索建议、防抖提交)
- 组合多个 ref / reactive 属性,又不想写冗长的数组监听列表


















