如果有任何問題或建議,歡迎隨時聯繫我:
各位 Vue 的魔法師們!昨天我們正式踏入了 Composition API 的世界,感受到了 <script setup>
帶來的清爽與便利。但要讓你的程式碼真正「活」起來,光有 <script setup>
還不夠,你還需要兩位超級英雄來幫你管理數據的「響應性」:那就是 ref
和 reactive
!
它們就像 Vue 響應式數據的雙生子,雖然都能讓你的數據在變化時自動更新畫面,但它們的脾氣、能力和適用場景卻大不相同。今天,我們就來深入了解這對兄弟,搞清楚它們的核心差異,以及在什麼時候該請誰出場,才能讓你的程式碼既優雅又高效!
ref
:單身貴族,什麼都能裝,但有點小脾氣想像 ref
就像一個萬能的「魔法盒子」,無論你把什麼東西丟進去——數字、字串、布林值,甚至是物件或陣列——它都能把它變成響應式的。但這個盒子有個小脾氣:當你在 <script>
裡面想打開它、取出或放入東西時,你必須禮貌地敲敲門,也就是加上 .value
。
ref
用來包裝任何型別的數據,使其變成響應式。它會返回一個 Ref
物件,這個物件只有一個屬性,就是 value
。當你修改 value
的值時,Vue 就能偵測到變化。
<script setup>
import { ref } from 'vue';
// 包裝基本型別
const count = ref(0); // 數字
const message = ref('Hello Vue!'); // 字串
const isActive = ref(true); // 布林值
// 包裝物件型別 (雖然可以,但通常有更好的選擇)
const user = ref({
name: 'Alice',
age: 30
});
const increment = () => {
count.value++; // 在 <script> 中訪問或修改 ref,必須用 .value
};
const changeName = () => {
user.value.name = 'Bob'; // 即使是物件,也還是要先 .value
};
</script>
<template>
<p>Count: {{ count }}</p> <!-- 在模板中,ref 會自動解包,不用 .value -->
<p>Message: {{ message }}</p>
<p>Is Active: {{ isActive }}</p>
<p>User Name: {{ user.name }}</p>
<button @click="increment">Increment Count</button>
<button @click="changeName">Change User Name</button>
</template>
ref
的優點<template>
中使用 ref
時,Vue 會自動幫你把 .value
拿掉,讓模板看起來更簡潔,就像普通變數一樣。<script>
中必須使用 .value
,這其實是一個很好的提示,讓你清楚知道你正在操作的是一個響應式數據,而不是普通的 JavaScript 變數。reactive
:物件專屬,深層響應的「魔法容器」reactive
就像一個專門為「物件」量身打造的「魔法容器」。你只能把物件(包括陣列)放進去,一旦放進去,這個物件的所有屬性(甚至是深層嵌套的屬性)都會變成響應式的。而且,當你在 <script>
裡面操作它時,你不需要像 ref
那樣加上 .value
,直接操作物件屬性就行了,非常直覺。
reactive
用來將一個 JavaScript 物件(或陣列)轉換成響應式物件。它內部是通過 ES6 的 Proxy
來實現的,這讓它能夠監聽物件內部屬性的增刪改查,實現「深層響應」。
<script setup>
import { reactive } from 'vue';
const state = reactive({
count: 0,
user: {
name: 'Alice',
age: 30,
address: {
city: 'Taipei'
}
},
items: ['apple', 'banana']
});
const increment = () => {
state.count++; // 直接操作屬性,不需要 .value
};
const changeCity = () => {
state.user.address.city = 'Kaohsiung'; // 深層屬性也能響應
};
const addItem = () => {
state.items.push('orange'); // 陣列操作也能響應
};
</script>
<template>
<p>Count: {{ state.count }}</p>
<p>User City: {{ state.user.address.city }}</p>
<ul>
<li v-for="item in state.items" :key="item">{{ item }}</li>
</ul>
<button @click="increment">Increment Count</button>
<button @click="changeCity">Change City</button>
<button @click="addItem">Add Item</button>
</template>
reactive
的優點<script>
中直接操作物件屬性,無需 .value
,寫法更自然。reactive
的陷阱:小心「解構」與「替換」!reactive
雖然好用,但它有兩個常見的「地雷」需要特別注意:
reactive
物件的屬性時,這些被解構出來的變數會失去響應性。因為它們已經脫離了 Proxy
的監聽範圍。
const state = reactive({ count: 0 });
let { count } = state; // count 變成普通變數,不再響應式
count++; // state.count 不會變
reactive
物件的引用,而不是修改其內部屬性,那麼新的物件也會失去響應性。
let state = reactive({ count: 0 });
state = { count: 1 }; // state 變成普通物件,不再響應式
正確的做法:應該使用 Object.assign()
或展開運算符來更新 reactive
物件的屬性,而不是替換整個物件。
Object.assign(state, { count: 1 }); // 正確
// 或者
// state.count = 1; // 更簡單直接
ref
vs reactive
:到底選誰?Vue 數據管理的最佳策略這是一個 Vue 開發者經常會遇到的選擇題。其實沒有絕對的「最好」,只有「最適合」的場景。以下是一些選擇建議:
特性 | ref |
reactive |
---|---|---|
包裝對象 | 任何型別(基本型別、物件、陣列) | 僅限物件型別(物件、陣列、Map、Set) |
訪問方式 | 在 <script> 中需 .value ,模板自動解包 |
直接訪問屬性,無需 .value |
響應深度 | 淺層響應(只監聽 value 的變化) |
深層響應(監聽物件內部所有屬性的變化) |
解構問題 | 無 | 有(解構會失去響應性) |
替換問題 | 無 | 有(替換整個物件會失去響應性) |
優先使用 ref
:
ref
是不二之選。ref
更安全,因為它沒有 reactive
的替換陷阱。<script>
中明確區分響應式數據和普通數據時,.value
是一個很好的視覺提示。當數據是複雜物件且需要深層響應時,考慮 reactive
:
reactive
可以提供更直覺的寫法(無需 .value
)。toRefs
使用,以解決解構失去響應性的問題。這就像給 reactive
穿上了一層「防彈衣」,讓你可以安全地解構其屬性。toRefs
的救贖:讓 reactive
也能優雅解構toRefs
是一個非常有用的工具函式,它可以將 reactive
物件的所有屬性轉換為 ref
物件。這樣,當你解構這些 ref
時,它們仍然保持響應性!
<script setup>
import { reactive, toRefs } from 'vue';
const state = reactive({
count: 0,
name: 'Vue'
});
// 使用 toRefs 將 state 的屬性轉換為 ref
const { count, name } = toRefs(state);
const increment = () => {
count.value++; // 現在 count 是一個 ref,需要 .value
};
const changeName = () => {
name.value = 'Vue 3'; // name 也是一個 ref
};
</script>
<template>
<p>Count: {{ count }}</p>
<p>Name: {{ name }}</p>
<button @click="increment">Increment</button>
<button @click="changeName">Change Name</button>
</template>
透過
toRefs
,你既能享受到reactive
的深層響應,又能避免解構失去響應性的問題,簡直是兩全其美!
isRef
、isReactive
、isProxy
。在除錯時非常有用。ref
和 reactive
的使用規範,避免程式碼風格混亂。ref
和 reactive
分別實現一個簡單的表單(例如包含姓名、年齡的表單),觀察它們在數據綁定和更新時的行為差異。特別注意 reactive
在解構時的響應性問題。ref
,又在什麼情況下,你會考慮 reactive
並搭配 toRefs
使用?今天我們深入探討了 Vue 響應式數據的兩位核心成員:ref
和 reactive
。它們各有優缺,適用於不同的場景。ref
像個萬能的「魔法盒子」,靈活且安全;reactive
則是物件專屬的「魔法容器」,提供深層響應,但需要小心解構和替換的陷阱。
掌握它們的核心差異,並學會搭配 toRefs
使用,你就能在 Vue 3 的世界裡,更自如地管理你的數據,寫出更健壯、更優雅的應用程式!
本日關鍵字回顧
ref
: 包裝任何型別數據,需 .value
訪問,模板自動解包。reactive
: 包裝物件型別數據,深層響應,解構易失響應性。.value
: 訪問 ref
包裝數據的屬性。Proxy
: reactive
內部實現深層響應的機制。toRefs
: 將 reactive
物件的屬性轉換為 ref
,解決解構問題。明天,我們將繼續探索 Vue 的響應式魔法,深入了解 computed
和 watch
這兩個強大的工具,看看它們如何在數據變化時,為我們提供更精細的控制!