在 Vue 的使用中你可能會看到 ref
跟 reactive
,
這是 Composition API 的核心,讓資料具備響應式。
但平平都是用來做變數的引用,到底差在哪裡確實是會讓人有點懷疑,
此篇文章就是用來釐清何種情況使用為較優解。
為避免第一次使用 Vue 的人看不懂
這邊還是簡單講解一下怎麼看響應式函數
註解
- 宣告一個常數,可以讓我們後續使用。
- 為這個常數賦予名稱。
- 響應式函數並接收一個參數初始值。
- 初始值為數字 0。
所以上面這句可以被理解為:
我們宣告了一個常數叫做 count
,它是一個響應式的物件,裡面存了一個初始值 0
。
言傳不如身教,話不多說,直接上手開始練習吧。
ref
<script setup>
import { ref } from 'vue'
const year = ref(2025)
console.log(year.value) // 2025
</script>
<template>
<h1>{{ year }}</h1>
</template>
reactive
<script setup>
import { reactive } from 'vue'
const date = reactive({year:2025})
console.log(date.year) // Proxy(Object) {year: 2025}
</script>
<template>
<h1>{{ date.year }}</h1>
</template>
ref
或 reactive
嗎?先說結論,如果你要 資料響應式變化 那就要用。
當你在模板中使用了一個 ref,然後改變了這個 ref 的值時,Vue 會自動檢測到這個變化,
並且相應地更新 DOM。
這是通過一個基於依賴追蹤的響應式系統實現的。
當一個組件首次渲染時,Vue 會追蹤在渲染過程中使用的每一個 ref。
然後,當一個 ref 被修改時,它會觸發追蹤它的組件的一次重新渲染。 - 為什麼要使用 ref?
在使用上單一值會使用 ref ,而遇到物件時用 reactive 會更好,
但是! 其實你全都用 ref 也無所謂,後面會講為什麼。
ref 可以接受任意資料型態包含物件,
但通常會使用基本資料類型 ( Primitive data types )
reactive 只能接受物件類型 ( Reference data types )
.value
?
我相信不管是第一次使用 Vue 或是使用一陣子的朋友都會覺得這個 .value
,
是一個很討厭的東西,都 2025 了要引用變數居然還要 .value
。
簡單來說就是由於原生 JavaScript 的限制,
我們需要透過 value
讓 Vue 有一個機會追蹤物件屬性變更,
但在這篇我們還不會過多講解這件事,
在後面響應式核心篇會再深入講解,讓我們銜接到 Alien-signals 時可以有更好的了解。
<template>
使用無須 .value
?Vue 會自動解包 模板中的響應式物件:
注意,在模板中使用
ref
時,我們不需要附加.value
。
為了方便起見,當在模板中使用時,ref
會自動解包 - ref()
reactive
就這麼沒人要嗎?
確實 ref
就足以應付大部分的場景,不過這邊我們可以來看一段 code。
<script setup>
import { ref } from 'vue';
const article = ref({
author: 'Yanya',
version: '3.5.0',
title: 'Progressive JavaScript Framework'
})
function updateVersion(){
article.value.version = '3.6.0'
}
</script>
<template>
<h1>{{article.title}}</h1>
<h2>Author : {{article.author}}</h2>
<p>version : {{article.version}}</p>
<button @click="updateVersion">點我更新版本</button>
</template>
這邊可以看到如果我用 ref
的話我就要 article.value.version
才有辦法更新裡面的屬性,
老實說真的有點煩。
於是我們稍微調整一下
+const article = reactive({
-const article = ref({
author: 'Yanya',
version: '3.5.0',
title: 'Progressive JavaScript Framework'
})
function updateVersion(){
+ article.value.version = '3.6.0'
- article.version = '3.6.0'
}
確實阿,會乾淨一點,那如果我今天多加一個狀況,我的物件裡面有 35 個屬性呢?
const article = reactive({
author: 'Yanya',
version: '3.5.0',
title: 'Progressive JavaScript Framework'
+ // 略...
})
function updateVersion(){
article.version = '3.6.0';
+ article.author = 'Evan';
+ article.title = 'Ref vs Reactive';
+ // 略...
}
聰明的你可能會想說,那不然我直接賦予他新的物件
不能替換整個對象:由於 Vue 的響應式跟蹤是通過屬性訪問實現的,因此我們必須始終保持對響應式對象的相同引用。這意味著我們不能輕易地“替換”響應式對象,因為這樣的話與第一個引用的響應性連接將丟失 - reactive() 的局限性
那我要怎麼做 QQ
這邊的話我們可以善用 Object.assign
將淺層物件複製到目標物件上
const article = reactive({
author: 'Yanya',
version: '3.5.0',
title: 'Progressive JavaScript Framework'
// 略...
})
+ const newInfo ={version:'3.6.0', author:'Evan', title:'Ref vs Reactive'}
function updateVersion(){
- article.version = '3.6.0';
- article.author = 'Evan';
- article.title = 'Ref vs Reactive';
+ Object.assign(article,newInfo)
}
如果我們今天需要用一個響應式物件跟模板連接,
為了避免和一般 ref 搞混,可能會嘗試在名稱上加上一個 Ref
,
用來表示這不是 Primitive Data,而是 Instance 或 HTMLElement,例如 xxRef = ref('')
。
然後模板區域使用它,還要 ref="inputRef"
,這樣有點繞遠路的感覺。
在 3.5 時推出了 useTemplateRef()
,主要是我們可以傳入自定義名稱,
然後模板區域直接 ref="input"
。
就我自己個人來講, 我會把需要綁定模板去做一些操作, 例如 .show
.on
,
那我就會使用 useTemplateRef
+ InstanceType
,這樣很好的展示出跟原始數據型態的 ref 差異
推薦使用時機 :
當你想要自定義 template ref 的名稱時可以使用
今天我們正式進入響應式系統篇章,為了打好基礎,響應式篇章會花比較大的篇幅做講解,
也透過了實際使用來了解 ref
和 reactive
的語法差異。
講解為什麼官方推薦使用 ref()
作為聲明響應式變數的 API,
經由實際案例來了解 reactive
的限制與優勢,
補充了 useTemplateRef
的使用方法。
可以看到官方所說的 reactive 的限制較多,包含傳入的值有限類型,
不能輕易替換物件值,解構將會失去響應式
由於這些限制,我們建議使用
ref()
作為聲明響應式狀態的主要 API。
所以結論就是使用 ref
作為響應式變數的引用在大多情況是較好的解, 除非你要深層的監聽物件內部屬性, 或是把多個相依賴的 ref
組合成一個物件, 那就可以考慮用 reactive
如果你喜歡這個系列或是想看我發瘋,歡迎按下 訂閱
一起走完這三十天吧。