03 ref、reactive 与 computed 响应式数据

📅 2026/8/6 13:46:17
03 ref、reactive 与 computed 响应式数据
ref、reactive 与 computed 响应式数据一、什么是响应式普通 JavaScript 变量改变后浏览器页面不会自动跟着变化letcount0;count1;如果页面已经显示了count仍然需要手动找到 DOM 并更新内容。Vue 的响应式系统解决的是修改状态 ↓ Vue 发现状态变化 ↓ 重新计算相关结果 ↓ 自动更新页面在 Vue 3 组合式 API 中最常见的响应式工具是ref()reactive()computed()。二、使用ref()保存状态import{ref}fromvue;constcountref(0);修改时使用count.value1;为什么需要.valueref()返回的不是原始数字而是一个包装对象{value:0}Vue 通过这个包装对象追踪读取和修改。模板中为什么不用.valuep{{ count }}/pVue 模板会自动解包ref因此模板中直接写变量名即可。三、ref()可以保存哪些内容1. 基础类型constloadingref(false);consttitleref(实时监控);constplaybackIndexref(0);2. 数组interfaceWarningItem{id:number;message:string;}constwarningsrefWarningItem[]([]);更新数组warnings.value.push({id:1,message:温度偏高});warnings.value[];3. 对象interfaceHeatInfo{heatId:string;converterNo:string;}constheatInforefHeatInfo|null(null);接口返回后赋值heatInfo.value{heatId:H20260805,converterNo:BOF-1};4. DOM 引用constcontainerRefrefHTMLElement();这类ref保存的是组件挂载后的 DOM 元素。四、使用reactive()保存对象import{reactive}fromvue;constformreactive({heatId:,displayMode:playback,autoRefresh:false});修改时不需要.valueform.heatIdH001;form.autoRefreshtrue;ref与reactive的基本区别ref 可以保存任何类型脚本中通过 .value 访问 reactive 主要包装对象直接访问对象属性初学阶段可以采用简单规则独立状态优先使用ref一组紧密相关的表单字段可以使用reactive项目已经形成统一风格时优先遵循项目约定。五、reactive的解构问题下面的写法可能破坏响应式联系conststatereactive({count:0});const{count}state;此时count是普通值。需要解构时可以使用import{toRefs}fromvue;const{count}toRefs(state);对于初学者避免随意解构reactive对象即可。六、什么是派生状态假设页面保存constdisplayModerefrealtime|playback(playback);是否处于实时模式可以由它推导constisRealtimeModecomputed(()displayMode.valuerealtime);displayMode是原始状态isRealtimeMode是派生状态。七、使用computed()import{computed,ref}fromvue;constpriceref(100);constcountref(2);consttotalcomputed(()price.value*count.value);模板中p总价{{ total }}/p当price或count变化时total自动重新计算。计算属性具有缓存只要依赖没有变化多次读取total.value不需要重复执行计算逻辑。因此适合把下面内容放到computed数据过滤状态判断显示文本多个来源的数据优先级风险等级当前帧列表汇总。八、从多个数据源选择当前数据实时页面经常同时具有实时快照历史回放基础详情。可以使用计算属性统一选择constheatMetaViewcomputed((){if(isRealtimeMode.value){returnsnapshot.value?.heat||playback.value?.heat||heatMeta.value;}returnplayback.value?.heat||heatMeta.value;});这样模板不需要反复判断strong{{ heatMetaView?.converterNo || -- }}/strong数据链变成snapshot / playback / heatMeta ↓ heatMetaView ↓ 模板九、根据原始信号计算风险状态constoffgasCoref(72);constwarningsrefstring[]([]);constriskClasscomputed((){if(warnings.value.includes(critical)){returncritical;}if(warnings.value.length0||offgasCo.value80){returnwarning;}returnnormal;});模板中div :classrisk-${riskClass} 当前状态{{ riskClass }} /div这比在模板中重复编写风险判断更清晰。十、只读计算属性与可写计算属性大多数计算属性是只读的constfullNamecomputed(()${firstName.value}${lastName.value});也可以定义get和setconstfullNamecomputed({get(){return${firstName.value}${lastName.value};},set(value:string){const[first,last]value.split( );firstName.valuefirst||;lastName.valuelast||;}});快速入门阶段应优先使用只读计算属性。可写计算属性只在确有双向转换需求时使用。十一、计算属性中不应该做什么计算属性应该保持“根据输入返回结果”。不建议在其中constdatacomputed((){fetch(/api/data);// 不推荐timersetInterval(...);// 不推荐count.value1;// 不推荐returncount.value;});发送请求、启动定时器、修改外部状态属于副作用应放到函数、生命周期或watch中。十二、一个完整示例template section h2{{ modeTitle }}/h2 p炉次{{ currentHeat?.heatId || -- }}/p p转炉{{ currentHeat?.converterNo || -- }}/p p :classrisk-${riskLevel}风险{{ riskText }}/p button clickdisplayMode realtime实时/button button clickdisplayMode playback回放/button /section /template script setup langts import { computed, ref } from vue; type DisplayMode realtime | playback; interface HeatInfo { heatId: string; converterNo: string; } const displayMode refDisplayMode(playback); const snapshotHeat refHeatInfo | null(null); const playbackHeat refHeatInfo | null({ heatId: H001, converterNo: BOF-1 }); const offgasCo ref(82); const isRealtimeMode computed( () displayMode.value realtime ); const modeTitle computed( () isRealtimeMode.value ? 实时监控 : 历史回放 ); const currentHeat computed( () isRealtimeMode.value ? snapshotHeat.value || playbackHeat.value : playbackHeat.value ); const riskLevel computed(() { return offgasCo.value 80 ? warning : normal; }); const riskText computed(() { return riskLevel.value warning ? 需要关注 : 正常; }); /script十三、常见误区1. 忘记.value脚本中loading.valuetrue;模板中{{ loading }}2. 把可以计算的结果重复存成ref如果一个值完全由其他状态决定应优先使用computed避免两份状态不同步。3. 在计算属性中修改依赖可能导致循环更新或难以追踪的副作用。4. 把所有对象都改成reactiveref和reactive没有绝对优劣。保持项目风格一致比机械选择更重要。十四、本章小结可以用下面的规则快速判断需要保存会变化的数据 → ref / reactive 需要根据已有数据得到新结果 → computed 需要数据变化后执行操作 → watch下一章将专门学习watch理解 Vue 如何在状态变化后执行请求、同步索引或更新第三方模块。