watchEffect 是 Vue 3 中自动追踪响应式依赖并执行副作用的工具,无需手动声明 deps,支持 onInvalidate 安全清理异步任务,适用于动态依赖与竞态控制场景。

watchEffect 是 Vue 3 响应式系统中一个轻量又强大的工具,它会自动收集你代码里访问的响应式数据,并在它们变化时重新执行。不需要手动列出依赖项,也不用担心遗漏或写错,特别适合处理带有异步操作的副作用逻辑。
自动追踪依赖,不用手写 deps 数组
与 watch 不同,watchEffect 不需要你显式传入依赖数组。它会在首次执行时“运行一遍”,过程中 Vue 自动记录所有被读取的响应式属性(比如 ref、reactive 中的字段),之后只要其中任意一个变化,就再次触发函数。
- 写法更简洁:直接传一个函数进去,没有额外配置项
- 避免漏掉依赖:比如忘了监听某个 ref 或嵌套对象里的字段
- 适合动态依赖场景:依赖项本身可能随状态变化而改变,比如根据用户权限决定监听哪个 API 参数
轻松处理异步副作用,避免竞态问题
在发起请求、定时器、事件监听等异步操作中,旧任务还没结束、新状态又来了,容易导致界面显示错乱或内存泄漏。watchEffect 提供了 onInvalidate 回调,帮你安全地中止上一次未完成的异步操作。
- 每次新副作用执行前,Vue 会先调用上一次注册的 onInvalidate 函数
- 你可以在里面取消请求(如 AbortController)、清除定时器(clearTimeout)、移除事件监听器
- 示例:输入搜索关键词时,自动取消前一次未返回的请求
注意执行时机和清理逻辑的写法
watchEffect 默认在组件更新前同步执行,但如果你在函数里用了 await 或 setTimeout,它就变成异步流程。这时候要特别注意:
- 不要在 watchEffect 内部直接 await 一个请求后更新 DOM——这可能导致响应不及时或重复渲染
- 清理函数必须在异步操作开始前注册,否则可能清理不到正在运行的任务
- 如果需要等待 DOM 更新后再执行(比如基于元素尺寸做计算),可以配合 nextTick
什么时候该用 watchEffect,而不是 watch?
当你想让逻辑“跟随状态自然流动”时,watchEffect 更合适:
- 副作用逻辑完全由响应式状态驱动,且依赖关系清晰、集中在一个函数内
- 需要响应多个分散的 ref,又不想一个个列出来
- 涉及异步 + 清理,比如搜索建议、自动保存、图表重绘
- watch 更适合精确控制:比如只监听某几个字段、需要旧值对比、或者依赖非响应式变量

















