vue.js 的 watch 用于响应式监听数据变化并执行副作用,适合异步操作;需掌握三种写法、监听时机、清除机制及防竞态技巧,避免内存泄漏与无限循环。

Vue.js 的 watch 用于响应式地监听数据变化并执行副作用,尤其适合处理异步操作(如 API 请求、防抖、节流、路由跳转等)。关键在于理解监听时机、清除机制和正确使用 watch 的三种写法(选项式、组合式、watchEffect),避免内存泄漏或重复触发。
监听单个响应式数据源(ref 或 reactive 属性)
适用于监听一个简单值(如搜索关键词、分页页码),配合防抖或条件判断控制异步行为:
- 使用
watch(source, callback, options),source可为 ref、getter 函数或响应式对象的路径字符串 - 设置
immediate: true可在初始化时立即执行一次回调 - 设置
deep: true才能深度监听 reactive 对象内部属性变化(仅对对象/数组有效) - 在回调中可访问新旧值:
watch(searchQuery, (newVal, oldVal) => { ... })
监听多个来源或复杂依赖(使用 watchEffect)
当副作用逻辑依赖多个响应式变量,且不需要旧值、也不关心具体哪个变了,watchEffect 更简洁直观:
分析 Vue 3 Composition API 使用情况——审计响应式模式、可组合函数设计、ref 与 reactive 的选择、计算属性、watcher 使用及组件……
- 自动收集依赖,无需显式指定监听源
- 每次依赖更新时重新运行整个函数体,适合“只要相关数据一变就刷新列表”这类场景
- 可通过
onInvalidate提前清理上一次未完成的异步任务(如取消 pending 的 axios 请求) - 示例:避免多次输入触发多个请求 —— 在
watchEffect内部用AbortController或标记位中断前序请求
处理异步副作用的关键细节
异步操作(如 fetch、timeout、router.push)容易引发竞态问题(race condition),必须主动管理生命周期:
- 手动取消未完成请求:在 watch 回调开始时保存当前请求的 abort controller 或设置 isCancelled 标志,在下一次触发前检查并终止
-
避免 setup 中直接 await:watch 回调是同步注册的,不能 async/await,需在内部用
async () => {...}包裹异步逻辑 - 组件卸载前清理:watch 返回的停止函数会在组件 unmount 时自动调用,但若用了 setTimeout/setInterval,需在 onInvalidate 或 onUnmounted 中手动清除
-
不要在 watch 中修改被监听的数据源,否则可能造成无限循环(除非加条件判断或使用
flush: 'post'延迟到 DOM 更新后)
组合式 API 中 watch 的典型结构
推荐在 setup() 或 setup() 的 onMounted 后使用,保持逻辑内聚:
- 监听 ref:
watch(count, (n) => console.log('count changed to', n)) - 监听 reactive 对象某字段:
watch(() => state.user.id, id => fetchUser(id)) - 监听整个 reactive 对象(深度):
watch(state, (cur, prev) => {...}, { deep: true }) - 配合 onBeforeUnmount 清理定时器:
onBeforeUnmount(() => clearInterval(timerId))
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










