vue3.x教程-watchEffect监视器

介绍

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)
  })
})

逻辑:

  1. 输入快速变化,每次触发 watchEffect 都会先执行清理函数;
  2. 防抖效果,只有停止输入500ms才真正发起请求。

其他清理场景:取消axios请求、移除window事件监听。

使用场景

适合用 watchEffect

  1. 一个副作用依赖多个响应式变量,不想手动罗列监听源;
  2. 只需要执行逻辑,不需要对比新旧值;
  3. 需要自动清理定时器/请求;
  4. 需要在DOM更新后执行操作(搭配 flush:post / watchPostEffect)。

适合用 watch

  1. 只监听单个/少量变量;
  2. 需要拿到更新前、更新后的值做对比;
  3. 只在数据变化时执行,不需要初始化执行。

原文出处:/show_1GW3hpCAhtxc.html