介绍
watchEffect 是 Vue3 组合式 API(setup / <script setup>)提供的自动依赖追踪监听函数:
- 不用指定监听哪个响应式变量,函数内部可直接使用;
- 变量发生变化时,函数会重新执行;
- 初始化时 立刻执行一次(区别于 watch 默认不立即执行)。
与 watch 的核心区别
| 特性 | watchEffect | watch |
|---|---|---|
| 依赖声明 | 自动收集,无需手动传数据源 | 必须手动指定监听源(ref/reactive/数组/函数) |
| 初次执行 | 默认立即执行 | 默认不执行,需加 immediate: true |
| 获取新旧值 | 无法直接拿到 oldVal、newVal | 回调参数可接收新旧值 |
| 精细控制 | 适合多依赖、逻辑简单场景 | 适合精准监听单一/少数变量、需要对比新旧值 |
基础语法
watchEffect(
effect: () => void, // 副作用函数(自动收集依赖)
options?: WatchEffectOptions // 配置项
) : () => void // 返回停止监听的函数
例子
如下图,监视 name、对象中的 score属性:
HTML代码:
<template>
姓名: <input type="text" v-model="name" />
<br>
年龄: <input type="text" v-model="student.age" />
<br>
密码: <input type="text" v-model="student.password" />
<br>
数学:<input type="text" v-model="student.score.shuxue" />
<br>
语文:<input type="text" v-model="student.score.yuwen" />
<br>
<button @click="modify">给score赋新值</button>
</template>
<script lang="ts" setup name='Student'>
// 导入 watchEffect
import { ref,reactive,watchEffect } from 'vue'
let name = ref('李雷')
// 对象
let student = reactive({
age:'',
password:'',
score:{
shuxue:'80',
yuwen:'70',
}
})
// 监视器,不需要指定监视哪个变量,也不能获取到原值
watchEffect(()=>{
// 在函数中,访问哪个响应式变量,就监听该变量
console.log("name:",name.value)
console.log("score:",student.score.shuxue)
})
// 给student的score属性赋新对象
function modify(){
name.value = '韩梅梅'
student.score = {
shuxue:'10',
yuwen:'20',
}
}
</script>
返回值:手动停止监听
watchEffect 返回一个停止函数,调用后不再监听依赖变化:
const stop = watchEffect(() => {
console.log(count.value)
})
// 手动停止
stop()
count.value++ // 不再打印日志
适用场景:弹窗、定时器、临时监听,销毁前主动取消。
WatchEffectOptions 配置项
1. flush:控制执行时机(非常常用)
可选值:'pre' / 'post' / 'sync'
pre(默认):DOM 更新前执行副作用post:DOM 更新完成后执行(需要操作更新后的 DOM 用这个)sync:同步执行,数据一改立刻运行(性能差,少用)
post 场景示例(获取更新后的DOM)
<template>
<p ref="textRef">{{ count }}</p>
</template>
<script setup>
import { ref, watchEffect } from 'vue'
const count = ref(0)
const textRef = ref(null)
// DOM更新后执行
watchEffect(() => {
if (textRef.value) {
console.log('DOM最新内容:', textRef.value.textContent)
}
}, { flush: 'post' })
count.value = 99
</script>
2. onTrack / onTrigger 调试钩子(开发排查依赖)
onTrack:依赖被收集时触发(初始化读取响应式变量)onTrigger:依赖变更触发副作用时触发
watchEffect(() => {
console.log(count.value)
}, {
onTrack(e) {
console.log('收集依赖', e.target, e.key)
},
onTrigger(e) {
console.log('依赖变更触发', e.target, e.key)
}
})
适合:不知道为什么 watchEffect 频繁执行,用来定位是哪个变量触发更新。
清除副作用(onCleanup)
场景:回调里有定时器、请求、事件监听,每次重新执行副作用前,需要清除上一次的操作,防止内存泄漏。
使用方式
副作用函数接收一个参数 onCleanup,注册清理回调:
const keyword = ref('')
watchEffect((onCleanup) => {
// 发起搜索请求
const timer = setTimeout(() => {
console.log('请求接口:', keyword.value)
}, 500)
// 每次执行前清除上一次定时器
onCleanup(() => {
clearTimeout(timer)
})
})
逻辑:
- 输入快速变化,每次触发 watchEffect 都会先执行清理函数;
- 防抖效果,只有停止输入500ms才真正发起请求。
其他清理场景:取消axios请求、移除window事件监听。
使用场景
适合用 watchEffect
- 一个副作用依赖多个响应式变量,不想手动罗列监听源;
- 只需要执行逻辑,不需要对比新旧值;
- 需要自动清理定时器/请求;
- 需要在DOM更新后执行操作(搭配 flush:post / watchPostEffect)。
适合用 watch
- 只监听单个/少量变量;
- 需要拿到更新前、更新后的值做对比;
- 只在数据变化时执行,不需要初始化执行。
