news 2026/8/6 13:46:08

04 watch 与 Vue 响应式数据流

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
04 watch 与 Vue 响应式数据流

watch 与 Vue 响应式数据流

一、为什么需要watch

computed适合根据已有状态计算结果,例如:

constisRealtimeMode=computed(()=>displayMode.value==='realtime');

但有些需求不是“得到一个新值”,而是“状态变化后执行一项操作”:

  • 切换模式后重新请求数据;
  • 当前帧变化后更新三维场景;
  • 路由参数变化后加载新的炉次;
  • 播放索引越界时自动修正;
  • 用户开启开关后启动定时器。

这类需求可以使用watch()

二、监听一个ref

import{ref,watch}from'vue';constdisplayMode=ref<'realtime'|'playback'>('playback');watch(displayMode,(newMode,oldMode)=>{console.log('旧模式:',oldMode);console.log('新模式:',newMode);});

displayMode.value改变时,回调函数执行。

三、监听计算属性

constisRealtimeMode=computed(()=>displayMode.value==='realtime');watch(isRealtimeMode,(isRealtime)=>{if(isRealtime){startPolling();}else{stopPolling();}});

只要传入的是 Vue 可以追踪的响应式来源,就能够监听。

四、监听对象属性

不能直接传普通值:

watch(state.count,()=>{});// 错误或无法正确监听

应传入 getter:

watch(()=>state.count,(count)=>{console.log(count);});

路由参数通常也采用这种方式:

watch(()=>route.query.heat_id,(newHeatId)=>{loadHeatData(String(newHeatId||''));});

五、同时监听多个来源

watch([temperature,oxygenFlow,tiltAngle],([newTemperature,newFlow,newTilt])=>{console.log(newTemperature,newFlow,newTilt);updateScene();});

大型可视化页面中,多个状态都会影响场景。可以将它们放进同一个数组:

watch([currentTime,riskClass,temperature,oxygenFlow,shellOpacity],()=>{scheduleSceneUpdate();});

这样可以明确表达:这些状态变化后,都需要更新外部渲染模块。

六、immediate:立即执行一次

默认情况下,watch只在数据变化后执行。

watch(heatId,(id)=>{loadHeatData(id);},{immediate:true});

immediate: true表示创建监听器时立即执行一次。

它适合“首次加载和后续变化使用同一逻辑”的场景。

不过,如果项目已经在onMounted()中明确加载数据,就不一定需要再使用immediate,避免重复请求。

七、深度监听deep

constform=reactive({user:{name:'',age:0}});watch(form,()=>{console.log('表单发生变化');},{deep:true});

深度监听会追踪嵌套属性,可能增加开销。

优先监听真正关心的字段:

watch(()=>form.user.name,(name)=>{console.log(name);});

不要因为“不确定改了哪个字段”就对大型对象一律使用deep: true

八、watchEffect()

watchEffect会立即执行,并自动收集回调中读取的响应式依赖:

watchEffect(()=>{console.log('当前模式:',displayMode.value);console.log('当前炉次:',heatId.value);});

区别可以简单理解为:

watch 明确指定监听谁,可获得新旧值 watchEffect 自动收集依赖,立即执行

真实业务中,如果依赖和触发条件需要非常明确,watch往往更容易维护。

九、computedwatch如何选择

使用computed

当目标是得到一个新值:

constprogressText=computed(()=>`${playbackIndex.value+1}/${frames.value.length}`);

使用watch

当目标是执行副作用:

watch(playbackIndex,()=>{updateExternalRenderer();});

判断规则:

“这个结果是什么?” → computed “变化后要做什么?” → watch

十、索引越界修正案例

回放数据重新加载后,帧数可能变少。如果当前索引超过数组范围,需要自动修正:

watch(playbackGroups,(groups)=>{constmaxIndex=Math.max(groups.length-1,0);if(playbackIndex.value>maxIndex){playbackIndex.value=maxIndex;}});

这里不是在计算一个显示值,而是在数据变化后修正另一个状态,因此适合使用watch

十一、模式切换案例

watch(displayMode,async(mode)=>{stopPlayback();stopRealtimePolling();if(mode==='realtime'){awaitloadSnapshot();startRealtimePolling();}else{awaitloadPlayback();}});

这段逻辑需要注意:

  1. 先停止旧模式任务;
  2. 再加载新模式数据;
  3. 最后启动新任务;
  4. 避免同时存在两个定时器。

十二、避免高频重复更新

如果多个响应式状态在同一时刻连续变化,直接调用昂贵更新可能重复执行。

可以借助requestAnimationFrame合并:

letupdateFrame:number|null=null;functionscheduleSceneUpdate(){if(updateFrame!==null){return;}updateFrame=requestAnimationFrame(()=>{updateFrame=null;updateScene();});}

监听器只负责安排更新:

watch([temperature,oxygenFlow,riskClass],scheduleSceneUpdate);

同一浏览器帧内无论触发多少次,都只执行一次真正更新。

十三、异步监听与过期结果

下面的监听可能出现请求竞争:

watch(heatId,async(id)=>{constdata=awaitgetHeatDetail(id);heat.value=data;});

用户快速切换heatId时,旧请求可能最后返回并覆盖新数据。

一种简单处理方式是记录请求编号:

letrequestId=0;watch(heatId,async(id)=>{constcurrentId=++requestId;constdata=awaitgetHeatDetail(id);if(currentId!==requestId){return;}heat.value=data;});

更完整的项目可以使用取消请求、请求门控或专门的数据请求库。

十四、停止监听

watch会返回停止函数:

conststop=watch(count,()=>{console.log(count.value);});stop();

在组件setup中创建的普通监听器会随组件卸载自动停止。但动态创建、跨组件保存或外部作用域中的监听仍需谨慎管理。

十五、常见误区

1. 用watch计算显示文本

watch(count,()=>{countText.value=`当前数量:${count.value}`;});

更适合:

constcountText=computed(()=>`当前数量:${count.value}`);

2. 在多个监听器中修改同一组状态

容易形成循环触发和难以定位的数据链。

3. 监听整个大型对象

优先监听实际需要的字段。

4. 模式切换时只启动新任务,不停止旧任务

会产生重复轮询、重复播放或资源泄漏。

十六、本章小结

大型 Vue 页面的典型响应式链是:

接口结果进入 ref ↓ computed 整理当前状态 ↓ watch 监听关键变化 ↓ 执行请求、同步索引或更新外部模块

下一章将学习生命周期,理解这些任务应该在页面的哪个阶段启动和清理。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/6 13:44:33

如何永久保存微信聊天记录:WeChatMsg完整导出与数据分析指南

如何永久保存微信聊天记录&#xff1a;WeChatMsg完整导出与数据分析指南 【免费下载链接】WeChatMsg 提取微信聊天记录&#xff0c;将其导出成HTML、Word、CSV文档永久保存&#xff0c;对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we…

作者头像 李华
网站建设 2026/8/6 13:44:00

LTC6268IS6#TRMPBF,500MHz超低偏置电流FET输入运算放大器

简介LTC6268IS6#TRMPBF 是 ADI 旗下凌力尔特推出的单通道 FET 输入高速运算放大器&#xff0c;采用 TSOT-23-6 小型封装、卷带出货&#xff0c;工业级工作温区覆盖 - 40℃至 85℃&#xff0c;专为微弱高阻抗信号的高速放大设计。该器件最核心优势是 fA 级超低输入偏置电流&…

作者头像 李华
网站建设 2026/8/6 13:43:00

3分钟解锁完整游戏体验:Wand-Enhancer免费增强指南

3分钟解锁完整游戏体验&#xff1a;Wand-Enhancer免费增强指南 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/GitHub_Trending/we/Wand-Enhancer 还在为WeMod Pro会员的高昂费用而犹…

作者头像 李华
网站建设 2026/8/6 13:42:41

Office Tool Plus 实战指南:高效部署与管理 Microsoft 365 全流程

之前为了给团队统一部署办公软件&#xff0c;尝试过各种官方渠道和第三方工具&#xff0c;要么流程繁琐&#xff0c;要么成本高昂。直到发现了 Office Tool Plus 这个神器&#xff0c;才发现原来 Microsoft 365 的部署和管理可以如此高效、灵活且低成本。本文将为你完整拆解 Of…

作者头像 李华
网站建设 2026/8/6 13:42:25

APK Installer:3分钟在Windows电脑上安装安卓应用的终极指南

APK Installer&#xff1a;3分钟在Windows电脑上安装安卓应用的终极指南 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否曾经想过在Windows电脑上直接运行安卓应…

作者头像 李华