在 Vue3 Composition API 中,ref 和 reactive 是構建響應式數據的核心工具。很多開發者在實際開發中會困惑:到底該用哪個?什麼時候該選 ref,什麼時候該用 reactive?其實答案很明確——尤雨溪早已給出方向:「ref 一把梭,不建議過度依賴 reactive」。本文將從本質區別、實戰場景、避坑指南三個維度,幫你徹底理清兩者的使用邏輯。
一、核心區別:兩種響應式的本質差異
要選對工具,首先要理解它們的底層邏輯:
ref:「全能選手」的響應式實現
ref 是 Vue3 推薦的響應式方案,本質是一個包裹對象,通過 .value 屬性訪問和修改內部值。它的核心優勢是「無限制」:
- 支持所有數據類型:基礎類型(字符串、數字、布爾值)、複雜類型(對象、數組、函數)
- 重新賦值不丟失響應式:直接修改
.value即可觸發頁面更新 - 模板中自動解包:在模板使用時無需手動寫
.value,開發體驗更流暢
// 基礎類型(ref 的核心場景)
const username = ref('張三')
const age = ref(22)
const isLogin = ref(false)
// 複雜類型(同樣支持)
const userInfo = ref({ name: '李四', role: 'admin' })
const articleList = ref([])
// 修改方式:通過 .value
username.value = '王五'
userInfo.value.role = 'superAdmin'
articleList.value = [{ id: 1, title: 'Vue3 響應式指南' }]
reactive:「對象專屬」的響應式代理
reactive 是基於 ES6 Proxy 實現的響應式代理,僅支持對象/數組類型,核心特點是「直接操作屬性」:
- 只能代理對象/數組:傳入基礎類型會直接報錯
- 重新賦值會丟失響應式:直接替換整個對象會切斷 Proxy 代理關係
- 模板中無需解包:直接通過屬性名訪問,無需
.value
// 正確用法:代理對象
const formData = reactive({
username: '',
password: '',
rememberMe: false
})
// 修改方式:直接操作屬性
formData.username = 'admin'
formData.rememberMe = true
// 錯誤用法:基礎類型報錯
// const count = reactive(0) // Uncaught TypeError: Cannot create proxy with a non-object as target
// 危險操作:重新賦值丟失響應式
let list = reactive(['蘋果', '香蕉'])
list = ['西瓜', '葡萄'] // 響應式失效,頁面不更新
二、實戰場景:精準選擇的 4 大原則
原則 1:基礎類型數據 → 必用 ref
reactive 無法處理字符串、數字、布爾值等基礎類型,強行使用會直接報錯。此時 ref 是唯一選擇:
// 正確:ref 處理基礎類型
const count = ref(0)
const searchKey = ref('')
const isLoading = ref(true)
// 錯誤:reactive 不支持基礎類型
// const isVisible = reactive(false) // 報錯
原則 2:需要重新賦值 → 必用 ref
開發中常見場景:異步請求數據、分頁切換、條件渲染數據替換等,都需要直接替換整個數據。此時 ref 的 .value 賦值特性至關重要:
// 異步請求數據(核心場景)
const userList = ref([])
const fetchUsers = async () => {
const res = await axios.get('/api/users')
userList.value = res.data // 重新賦值仍保持響應式
}
// 分頁切換
const currentPage = ref(1)
const pageData = ref([])
const changePage = (newPage) => {
currentPage.value = newPage
pageData.value = getPageData(newPage) // 直接替換數據
}
如果用 reactive 處理這類場景,必須額外嵌套一層對象,代碼冗餘且易出錯:
// reactive 處理重新賦值的繁瑣寫法
const state = reactive({
userList: [],
currentPage: 1
})
const fetchUsers = async () => {
const res = await axios.get('/api/users')
state.userList = res.data // 只能修改屬性,不能替換 state 本身
}
原則 3:固定對象(僅改屬性)→ 可選 reactive
如果數據是固定結構的對象,且後續只會修改內部屬性、不會整體替換,reactive 能提供更簡潔的語法(無需 .value):
// 表單數據(典型場景)
const loginForm = reactive({
username: '',
password: '',
rememberMe: false
})
// 編輯用户信息
const editUser = reactive({
id: 1,
name: '張三',
age: 25,
avatar: ''
})
// 直接修改屬性,簡潔直觀
loginForm.username = 'test@xxx.com'
editUser.age = 26
原則 4:不確定場景 → 無腦用 ref
ref 的兼容性極強,無論基礎類型還是複雜類型、無論是否需要重新賦值,都能完美應對。對於不確定的場景,直接用 ref 永遠不會出錯:
// 未知數據類型
const unknownData = ref(null)
// 可能後續替換的對象
const dynamicObj = ref({ a: 1, b: 2 })
// 後續需要整體替換時直接賦值
dynamicObj.value = { c: 3, d: 4 } // 響應式不受影響
三、避坑指南:這些錯誤千萬別犯
坑 1:reactive 直接重新賦值
這是最常見的錯誤!直接替換 reactive 代理的對象,會導致響應式失效:
// 錯誤示例
let goodsList = reactive(['手機', '電腦'])
// 重新賦值後,goodsList 變成普通數組,失去響應式
goodsList = ['平板', '耳機']
// 正確寫法(用 ref)
const goodsList = ref(['手機', '電腦'])
goodsList.value = ['平板', '耳機'] // 保持響應式
坑 2:ref 在腳本中忘記寫 .value
ref 的響應式依賴 .value 觸發,腳本中修改時必須加 .value,否則無法更新:
const count = ref(0)
// 錯誤:未加 .value,數據不更新
count = 1
// 正確:通過 .value 修改
count.value = 1
坑 3:用 reactive 包裹基礎類型
reactive 僅支持對象/數組,傳入基礎類型會直接報錯,務必避開:
// 錯誤:基礎類型不能用 reactive
const isDarkMode = reactive(false) // 報錯
// 正確:用 ref 處理
const isDarkMode = ref(false)
四、黃金總結:記住這 3 句話
- 基礎類型(字符串/數字/布爾)→ 用 ref;
- 需要重新賦值(xxx = 新數據)→ 用 ref;
- 固定結構對象(僅改屬性)→ 可選 reactive,不確定就用 ref。
Vue3 設計 ref 時就是為了彌補 reactive 的侷限性,它的兼容性和易用性都更優。遵循「ref 優先」的原則,既能減少踩坑概率,也能讓代碼風格更統一。畢竟尤雨溪都推薦「ref 一把梭」,跟着官方方向走準沒錯!