尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

04 watch 与 Vue 响应式数据流

04 watch 与 Vue 响应式数据流 watch 与 Vue 响应式数据流一、为什么需要watchcomputed适合根据已有状态计算结果例如constisRealtimeModecomputed(()displayMode.valuerealtime);但有些需求不是“得到一个新值”而是“状态变化后执行一项操作”切换模式后重新请求数据当前帧变化后更新三维场景路由参数变化后加载新的炉次播放索引越界时自动修正用户开启开关后启动定时器。这类需求可以使用watch()。二、监听一个refimport{ref,watch}fromvue;constdisplayModerefrealtime|playback(playback);watch(displayMode,(newMode,oldMode){console.log(旧模式,oldMode);console.log(新模式,newMode);});当displayMode.value改变时回调函数执行。三、监听计算属性constisRealtimeModecomputed(()displayMode.valuerealtime);watch(isRealtimeMode,(isRealtime){if(isRealtime){startPolling();}else{stopPolling();}});只要传入的是 Vue 可以追踪的响应式来源就能够监听。四、监听对象属性不能直接传普通值watch(state.count,(){});// 错误或无法正确监听应传入 getterwatch(()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避免重复请求。七、深度监听deepconstformreactive({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往往更容易维护。九、computed和watch如何选择使用computed当目标是得到一个新值constprogressTextcomputed(()${playbackIndex.value1}/${frames.value.length});使用watch当目标是执行副作用watch(playbackIndex,(){updateExternalRenderer();});判断规则“这个结果是什么” → computed “变化后要做什么” → watch十、索引越界修正案例回放数据重新加载后帧数可能变少。如果当前索引超过数组范围需要自动修正watch(playbackGroups,(groups){constmaxIndexMath.max(groups.length-1,0);if(playbackIndex.valuemaxIndex){playbackIndex.valuemaxIndex;}});这里不是在计算一个显示值而是在数据变化后修正另一个状态因此适合使用watch。十一、模式切换案例watch(displayMode,async(mode){stopPlayback();stopRealtimePolling();if(moderealtime){awaitloadSnapshot();startRealtimePolling();}else{awaitloadPlayback();}});这段逻辑需要注意先停止旧模式任务再加载新模式数据最后启动新任务避免同时存在两个定时器。十二、避免高频重复更新如果多个响应式状态在同一时刻连续变化直接调用昂贵更新可能重复执行。可以借助requestAnimationFrame合并letupdateFrame:number|nullnull;functionscheduleSceneUpdate(){if(updateFrame!null){return;}updateFramerequestAnimationFrame((){updateFramenull;updateScene();});}监听器只负责安排更新watch([temperature,oxygenFlow,riskClass],scheduleSceneUpdate);同一浏览器帧内无论触发多少次都只执行一次真正更新。十三、异步监听与过期结果下面的监听可能出现请求竞争watch(heatId,async(id){constdataawaitgetHeatDetail(id);heat.valuedata;});用户快速切换heatId时旧请求可能最后返回并覆盖新数据。一种简单处理方式是记录请求编号letrequestId0;watch(heatId,async(id){constcurrentIdrequestId;constdataawaitgetHeatDetail(id);if(currentId!requestId){return;}heat.valuedata;});更完整的项目可以使用取消请求、请求门控或专门的数据请求库。十四、停止监听watch会返回停止函数conststopwatch(count,(){console.log(count.value);});stop();在组件setup中创建的普通监听器会随组件卸载自动停止。但动态创建、跨组件保存或外部作用域中的监听仍需谨慎管理。十五、常见误区1. 用watch计算显示文本watch(count,(){countText.value当前数量${count.value};});更适合constcountTextcomputed(()当前数量${count.value});2. 在多个监听器中修改同一组状态容易形成循环触发和难以定位的数据链。3. 监听整个大型对象优先监听实际需要的字段。4. 模式切换时只启动新任务不停止旧任务会产生重复轮询、重复播放或资源泄漏。十六、本章小结大型 Vue 页面的典型响应式链是接口结果进入 ref ↓ computed 整理当前状态 ↓ watch 监听关键变化 ↓ 执行请求、同步索引或更新外部模块下一章将学习生命周期理解这些任务应该在页面的哪个阶段启动和清理。
返回列表