选 watch 还是 watcheffect 取决于具体需求:需新旧值对比、条件过滤或深度监听时用 watch;依赖动态变化、写法极简或自动追踪响应式访问时用 watcheffect。

选 watch 还是 watchEffect,关键不在“哪个更高级”,而在于“你要解决什么问题”。两者设计初衷不同:一个是精准狙击,一个是区域扫描。
需要新旧值对比或条件过滤?用 watch
当逻辑依赖变化前后的状态(比如防抖、跳过空值、只在值真正改变时执行),watch 的回调天然支持 (newVal, oldVal) 参数:
- 表单校验:仅当输入从空变非空时触发验证
- 搜索请求:忽略连续输入中的中间空值或重复值
- 状态同步:旧值为 'loading'、新值为 'success' 时才更新 UI
watchEffect 拿不到 oldVal,这类判断只能靠手动缓存,既冗余又易错。
依赖动态变化或写法要极简?用 watchEffect
当回调里访问的响应式数据会随条件分支变化(比如 v-if 对应的 ref 在某些状态下才被读取),watchEffect 会自动追踪实际用到的依赖:
- 条件渲染下的数据加载:仅当
enabled.value === true时才读取list.value,watchEffect 会等条件满足后才开始监听它 - 快速初始化 + 响应:组件一挂载就要拉一次数据,之后再响应变化,无需额外配
immediate: true - 多字段组合计算:如
fullName = firstName + lastName,直接在回调里拼接,自动响应任一字段变更
用 watch 实现类似逻辑,要么得手动维护依赖数组,要么漏掉某个分支里的响应式访问。
要深度监听对象或控制执行时机?watch 更可靠
watch 支持 { deep: true } 和 { immediate: true } 等配置,且对 reactive 对象属性、计算属性、getter 函数都支持明确声明:
- 监听一个嵌套对象的任意深层变动(如
user.profile.address.city) - 首次加载时就执行副作用(如初始化图表),同时保留后续响应能力
- 监听 computed 返回值,或只监听 reactive 中某几个特定字段
watchEffect 不支持 deep,也不接受配置项;它的“深度”仅限于函数内直接访问的响应式引用本身——对象内部属性变化若未被显式读取,就不会触发。
需要手动停止或清理异步请求?两者都支持,但方式一致
无论是 watch 还是 watchEffect,调用时都返回一个 stop() 函数,可用于主动取消监听:
- 路由离开前停掉定时器或未完成的 API 请求
- 弹窗关闭时清理关联的 watchEffect 副作用
- 通过
onInvalidate回调,在下次执行前取消上一轮未完成的异步操作(如搜索联想)
注意:组件卸载时,Vue 会自动清理所有监听器,手动 stop 主要用于提前控制生命周期。











