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()
}
相关推荐
swipe1 小时前
10|(前端转全栈)库存扣减为什么最容易出事故?SKU、并发与原子更新
前端·后端·全栈
huabuyu1 小时前
几百 MB 的文件为什么等几分钟才能打开?文件分片下载与渐进预览原理
前端·javascript
虚惊一场1 小时前
麻将桌上的并发控制:扫码进房、乐观版本与零和结算
前端·javascript
巴勒个啦1 小时前
从需求到上线:记录一次完全由 AI 辅助完成的小产品全流程
java·前端
无人生还1 小时前
从 Vue3 到 React · 快速上手系列第 6 篇:状态管理 useState 与 useReducer
前端·vue.js·react.js
hunterandroid1 小时前
Room 并发写入与事务一致性:从数据竞争到可靠落地
前端
天才熊猫君1 小时前
自动给所有 catch 块补上错误上报:从原理到落地
前端·javascript
朱涛的自习室2 小时前
Munk AI 桌面端「预告」
android·前端·人工智能
程序员包打听2 小时前
从 npx 到 moonx,moonbit 的野心与展望
前端·后端