vue3中的watchEffect()监听,什么时候监听,什么时候清理,什么时候停止

先写一个vue3的完整示例,取名为home.vue

javascript 复制代码
<script setup>
import { ref,watchEffect,onMounted,onUnmounted} from 'vue'
const count=ref(0);
const userid=ref(1);
const userData=ref(null);
const timer=ref(0);

//同步监听,只是读取数据或是计算属性没有必要进行清理
watchEffect(()=>{
    console.log(`当前count:${count.value},userid:${userid.value}`);
})
//异步获取数据,如获取后端数据,或是有定时器之类的setTimeout(),便要做清理
watchEffect(async (onInvalidate)=>{
    const id=userid.value;
    console.log(`开始获取用户${id}的数据...`);
    //模拟异步请求
    const controller=new AbortController();	   //创建一个"取消控制器"
    try{
        const timeoutid=setTimeout(()=>{
            userData.value={id,username:`用户${id}`}
            console.log(`用户${id}数据获取完成`)
        },1000);

        //清理函数:在effect重新执行前或停止时调用
        onInvalidate(()=>{
            clearTimeout(timeoutid);
            controller.abort()			//如果是fetch获取后端数据或定时器,立刻中断
            console.log(`清理用户${id}的pending请求`)
        })
    }catch(e)
    {
        if(e.name==='AbortError')
        {
            console.log('请示被取消');
        }
    }
})

//手动停止watchEffect
let stopTimerWatch;

onMounted(()=>{
    stopTimerWatch=watchEffect(()=>{
        console.log(`计时器:${timer.value}`)
    })
})
onUnmounted(() => {
  // 组件卸载时手动停止,防止内存泄漏
  stopTimerWatch && stopTimerWatch()
  console.log('timer 的 watchEffect 已停止')
})


//辅助函数
const increment=()=>count.value++;
const changeuser=()=>userid.value++;
const startTimer=()=>{
    const interval = setInterval(() => timer.value++, 1000)
    // 5秒后停止 timer 的 watchEffect
    setTimeout(() => {
        stopTimerWatch && stopTimerWatch()
        clearInterval(interval)
        console.log('手动停止了 timer 监听')
    }, 5000)
}
</script>
<template>
    
    <div>
        <h4>count:{{count}}</h4>
        <button @click="increment">+1</button>
        <h4>用户ID:{{userid}}</h4>
        <button @click="changeuser">切换用户</button>
        <p>用户数据:{{userData}}</p>
        <h4>计时器:{{timer}}</h4>
        <button @click="startTimer">开始计时(5秒后自动停止监听)</button>
    </div>
</template>
<style scoped>

</style>

不需要清理的情况

//只是纯计算/读取,没有遗留任何"副作用",所以不需要清理

javascript 复制代码
import { ref, watchEffect } from 'vue'

const count = ref(0)
const double = ref(0)

// 纯同步:只是读取 count,计算 double
// 没有产生"副作用"(定时器、请求、事件等),所以不需要 onInvalidate
watchEffect(() => {
  double.value = count.value * 2
  console.log('count 变了,double =', double.value)
})

异步需要清理的情况

javascript 复制代码
import { ref, watchEffect } from 'vue'

const keyword = ref('vue')
const results = ref([])

watchEffect(async (onInvalidate) => {
  const currentKeyword = keyword.value
  
  // 产生副作用:发起网络请求
  const controller = new AbortController()
  
  try {
    const res = await fetch(`/api/search?q=${currentKeyword}`, {
      signal: controller.signal
    })
    const data = await res.json()
    
    // ⚠️ 竞态问题:如果 keyword 快速变化,旧的请求可能后返回
    // 需要确保只采用最新请求的结果
    if (currentKeyword === keyword.value) {
      results.value = data
    }
    
  } catch (e) {
    // 忽略取消请求的错误
  }
  
  // 🔧 清理:在 effect 重新执行前,取消上一个未完成的请求
  onInvalidate(() => {
    controller.abort()
  })
})

同步也需要清理的情况

javascript 复制代码
import { ref, watchEffect } from 'vue'

const visible = ref(false)

watchEffect((onInvalidate) => {
  if (visible.value) {
    // 同步产生了副作用:添加事件监听
    const handler = (e) => console.log('点击了', e.target)
    document.addEventListener('click', handler)
    
    // 🔧 必须清理,否则监听会越积越多
    onInvalidate(() => {
      document.removeEventListener('click', handler)
    })
  }
})

终止stop使用时机

javascript 复制代码
import { ref, watchEffect, onUnmounted } from 'vue'

const count = ref(0)

const stop = watchEffect(() => {
  console.log(count.value)
})

// 情况1:组件卸载时停止,防止内存泄漏
onUnmounted(() => {
  stop()
})

// 情况2:满足某个条件后不再需要监听
if (someCondition) {
  stop()
}
相关推荐
爱敲代码的小杨.4 分钟前
【Spring】Spring Web MVC
前端·spring·mvc
我的世界洛天依14 分钟前
【胡桃讲编程】JS 入门第 1 课:Hello World,开启你的 JavaScript 编程之旅
javascript
是立不是利24 分钟前
深入理解JavaScript事件委托
开发语言·前端·javascript
晴天1633 分钟前
React 版本迭代解析:从15到19 核心差异-Day40
前端·react.js·前端框架
APItesterCris1 小时前
告别人工盯品!借助 Open‑Claw 快速搭建电商商品全自动监控与数据分析系统(完整实操代码)
java·大数据·前端·数据库
啊阿狸不会拉杆1 小时前
《计算机网络-自顶向下方法》6.7 回顾:Web页面请求的历程 读书笔记
前端·计算机网络
李少兄2 小时前
记一次 IDEA 打开 Vue 项目后目录“闪现即消失“ 问题排查
java·vue.js·intellij-idea
云上工程笔记2 小时前
四柱记账法和复式记账法有什么区别?复式记账为什么更适合查错和对账
大数据·前端·人工智能
恋猫de小郭2 小时前
Dart Skills CLI 1.0 :AI 时代的 Dart 交付支持
android·前端·flutter
Hilaku2 小时前
为什么技术极强的前端,往往当不好前端 Team Leader?
前端·javascript·程序员