watchEffect 是 Vue 3 中自动追踪响应式依赖并立即执行的副作用监听工具,支持异步清理、无需手动声明依赖,适用于日志、同步等场景,区别于 watch 的显式依赖与旧值支持。

watchEffect 是 Vue 3 中一个非常实用的响应式副作用监听工具,它能自动追踪内部使用的响应式数据,并在数据变化时重新执行。相比传统的 watch,它更简洁、更“声明式”,也更适合处理依赖关系不固定或逻辑较集中的场景。
自动追踪依赖:不用手动写依赖数组
watchEffect 会自动收集其执行过程中读取的所有响应式属性(ref、reactive、computed 等),形成依赖关系。只要这些值后续发生变化,函数就会被重新调用。
例如:
const count = ref(0)
const message = ref('hello')
watchEffect(() => {
console.log('count:', count.value)
console.log('message:', message.value)
})
// 初始执行一次;之后只要 count 或 message 改变,都会触发
你不需要像 watch([count, message], ...) 那样显式列出依赖项,Vue 内部通过 Proxy 的 get 拦截完成自动追踪。
Vue 3 组合式 API 与 最佳实践,涵盖代码组织、useXxx 模式、组合式函数设计、Store 集成、响应式优化及功能抽取。
立即学习“前端免费学习笔记(深入)”;
异步清理机制:应对频繁触发和过期回调
当 watchEffect 执行异步操作(如 API 请求)时,可能前一次请求还没完成,新一次依赖更新又触发了新请求。为避免“竞态问题”(比如旧响应覆盖新结果),watchEffect 提供了一个 清理函数 —— 它会在下一次副作用执行前被调用。
用法很简单:在 watchEffect 回调中返回一个函数即可:
watchEffect((onInvalidate) => {
const timer = setTimeout(() => {
console.log('请求完成')
}, 1000)
// 返回清理函数,在下次执行前自动调用
onInvalidate(() => {
clearTimeout(timer)
console.log('已取消上一次请求')
})
})
- 清理函数只在副作用 被重新执行前 调用,首次执行不会触发
- 如果副作用是同步的(无异步逻辑),通常不需要清理函数
- 清理函数本身不能是异步的,但可以用来取消 Promise、清除定时器、终止 fetch 请求等
与 watch 的关键区别
- 依赖声明方式:watchEffect 自动追踪;watch 需显式指定源(支持函数、ref、数组、对象)
-
初始执行时机:watchEffect 默认立即执行一次;watch 默认不执行(除非加
immediate: true) - 旧值获取:watchEffect 不提供旧值;watch 的回调可接收新/旧值,适合做差异判断
- 适用场景:watchEffect 更适合“响应式副作用”,如日志、状态同步、自动保存;watch 更适合“监听变化并做出条件响应”,如表单校验、路由守卫
注意事项与最佳实践
- 避免在 watchEffect 中修改它所依赖的响应式数据,否则可能引发无限循环(Vue 会抛出警告)
- 不要在条件分支中读取响应式变量(如
if (flag) console.log(state.count)),否则该变量不会被稳定追踪 - 若需访问组件实例或 this,请确保在 setup() 中正确使用,或改用
getCurrentInstance()(仅限高级用法) - 对性能敏感的场景,注意 watchEffect 的执行频率,必要时用
watch+deep或flush: 'post'控制时机

















