
Vue 中 ref 和 reactive 有什么區別該用哪個一句話總結ref 適合「基本類型 需要重新賦值」的場景reactive 適合「對象/數組 不需要整體替換」的場景。記不住基本類型用 ref對象用 reactive需要整體替換的用 ref 包對象就這么簡單正文目錄ref 和 reactive 的核心區別是什么5 大高頻場景 代碼示例萬能兜底ref vs reactive 決策表預防 checklist不再踩坑一句話總結一、ref 和 reactive 的核心區別是什么問題背景Vue 3 的響應式系統基于Proxy提供了ref和reactive兩種創建響應式數據的 API很多開發者分不清什么時候用哪個。對比項refreactive支持類型任意類型基本類型 對象僅對象/數組訪問方式.value模板中自動解包直接訪問屬性重新賦值? 直接xxx.value newVal? 丟失響應式解構需要配合toRefs直接解構會丟失響應式模板中使用自動解包無需.value直接使用深層響應? 默認深層? 默認深層import{ref,reactive}fromvue// ? ref基本類型constcountref(0)count.value// JS 中需要 .value// 模板中{{ count }} 自動解包不需要 .value// ? reactive對象conststatereactive({name:Claw,age:3})state.age4// 直接修改屬性// ? reactive 整體替換 → 丟失響應式statereactive({name:New,age:5})// 不報錯但響應式斷了二、5 大高頻場景 代碼示例場景 1計數器 / 開關 → 用 ref基本類型需要頻繁修改用 ref 最直觀。// ? 正確基本類型用 refconstisLoadingref(false)constcountref(0)constmessageref(hello)functiontoggle(){isLoading.value!isLoading.value}// ? 錯誤reactive 不支持基本類型constcountreactive(0)// Vue 警告value should be an object場景 2表單對象 → 用 reactive多個關聯字段組成一個對象不需要整體替換用 reactive 更自然。script setup import { reactive } from vue // ? 表單對象用 reactive const form reactive({ username: , password: , remember: false }) function submit() { console.log(form.username, form.password) } function reset() { // ?? 逐字段重置不能整體替換 form.username form.password form.remember false } /script// ? 錯誤整體替換丟失響應式functionreset(){form{username:,password:,remember:false}// 響應式斷了}場景 3需要整體替換的對象 → 用 ref從接口拿數據后整體賦值用 ref 包對象更安全。// ? 正確接口數據用 ref方便整體替換constuserInforef(null)asyncfunctionfetchUser(){constresawaitapi.getUser()userInfo.valueres.data// ? 整體替換沒問題}// ? 麻煩reactive 要逐字段賦值constuserInforeactive({})asyncfunctionfetchUser(){constresawaitapi.getUser()Object.assign(userInfo,res.data)// 能用但啰嗦// 或者逐字段userInfo.name res.data.name ...}場景 4解構響應式對象 → 用 toRefs 配合 reactivereactive 解構后會丟失響應式必須用toRefs包裝。script setup import { reactive, toRefs } from vue const state reactive({ name: Claw, age: 3 }) // ? 直接解構丟失響應式 // const { name, age } state // ? toRefs 解構保持響應式 const { name, age } toRefs(state) /script// ref 則不需要 toRefsconstcountref(0)// 模板中直接用 {{ count }}無需解構場景 5watch 監聽 → ref 和 reactive 行為不同import{ref,reactive,watch}fromvue// ? refwatch 默認監聽 .value 的變化constcountref(0)watch(count,(newVal,oldVal){console.log(${oldVal}→${newVal})})// ? reactivewatch 默認深層監聽conststatereactive({count:0})watch(state,(newVal){console.log(state changed,newVal.count)})// ?? watch reactive 的某個屬性 → 需要用 getterwatch(()state.count,(newVal,oldVal){console.log(${oldVal}→${newVal})})// ?? ref 包對象 → 默認不深層監聽需要 deepconstobjref({count:0})watch(obj,(newVal){console.log(newVal)// obj.value {} 時觸發},{deep:true})// 修改 obj.value.count 需要 deep三、萬能兜底ref vs reactive 決策表場景用什么原因基本類型string/number/booleanrefreactive 不支持基本類型獨立的對象/數組不需要整體替換reactive訪問自然不需要.value接口返回的數據需要整體替換ref可以直接xxx.value newData表單對象reactive字段關聯逐字段操作需要解構使用的對象reactivetoRefsref 不需要解構定時器/ DOM 引用ref存任意值不觸發渲染組合式函數返回值ref調用方可以解構后保持響應式萬能決策流程是基本類型嗎 → 是 → 用 ref → 否 → 需要整體替換嗎 → 是 → 用 ref包對象 → 否 → 用 reactive// 萬能模板import{ref,reactive}fromvue// 基本類型constloadingref(false)consttotalref(0)// 對象 - 不需要整體替換constformreactive({name:,email:})// 對象 - 需要整體替換接口數據constlistref([])asyncfunctionloadData(){list.valueawaitapi.getList()}四、預防 checklist不再踩坑基本類型必須用ref不要用reactivereactive對象不要整體替換用Object.assign或逐字段賦值接口數據整體賦值 → 用ref包對象解構reactive→ 必須用toRefs或toRef模板中ref自動解包JS 中必須.valuewatch監聽reactive屬性 → 用 getter 函數() state.xxxwatch監聽ref對象的深層變化 → 加{ deep: true }組合式函數返回值優先用ref方便調用方解構五、一句話總結基本類型用 ref固定結構對象用 reactive需要整體替換的對象用 ref 包裹——記不住就看要不要重新賦值要重新賦值就用 ref。最后問候親愛的朋友們并邀請你們閱讀我的全新著作 《Vue.js 3企業級項目開發實戰微課視頻版》