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()
}
相关推荐
卸任11 小时前
Vibe coding工具使用心得
前端·ai编程
brien912 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance12 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M12 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写12 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李12 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易12 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding13 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马13 小时前
前沿视界
前端
kyriewen13 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员