Vue 3.5 基於 Proxy (代理)重新設計了響應式系統,所有在 ref
或 reactive
包裝的資料,一旦改變,就會自動觸發 DOM 更新,保持「資料驅動 UI」的原則。
在 Vue 3 中常用的響應式 API 主要是:
ref()
=> 適合單一值或希望明確控制的情境reactive()
=> 適合物件/陣列ref
和 reactive
是什麼ref
定義 :ref
會建立一個「帶有 .value
屬性」的響應式包裝,通常用於基本型別(number、string、boolean)或需要整個物件替換的情境。
特點 :
xxx.value
。{{ count }}
即可。<script lang="ts" setup>
import { ref } from 'vue'
const count = ref<number>(0)
function increment(): void {
count.value++ // JS/TS 內部必須用 .value
}
</script>
<template>
<div>
<p>目前數字:{{ count }}</p> <!-- 模板中自動解包 -->
<button @click="increment">+1</button>
</div>
</template>
reactive
定義 :
reactive
會將物件或陣列轉換成 深層的 Proxy 響應式物件,可以像操作普通物件一樣存取/修改,Vue 會自動追蹤依賴。
特點 :
state.count++
修改,不需要 .value
。<script lang="ts" setup>
import { reactive } from 'vue'
interface User {
name: string
age: number
}
const state = reactive({
count: 0,
user: {
name: 'kuku',
age: 30
} as User
})
function increment(): void {
state.count++
}
</script>
<template>
<div>
<p>{{ state.count }}</p>
<p>{{ state.user.name }} ({{ state.user.age }})</p>
<button @click="increment">+1</button>
</div>
</template>
ref
和 reactive
特性 | ref |
reactive |
---|---|---|
適合情境 | 單一值、原始型別 (number, string, boolean) | 物件、陣列 |
存取方式 | JS/TS 內用 .value ,模板中自動解包 |
直接存取屬性,無需 .value |
是否深層響應 | 單一值響應;若包物件,只是淺層包裝 | 深層響應(內層屬性也響應) |
解構問題 | 不會失去響應 | 直接解構會失去響應,需要 toRefs |
型別推斷 (TS) | 適合簡單型別 | 適合物件型別 |
在實務上,ref
和 reactive
經常搭配:
<script lang="ts" setup>
import { ref, reactive, toRefs } from 'vue'
const count = ref<number>(0)
const user = reactive({
name: 'kuku',
age: 30
})
// 正確解構 reactive
const { name, age } = toRefs(user)
function growUp(): void {
age.value++
}
</script>
<template>
<div>
<p>Count: {{ count }}</p>
<p>User: {{ name }} ({{ age }})</p>
<button @click="count++">+1</button>
<button @click="growUp">Age +1</button>
</div>
</template>
reactive
物件會失去響應const state = reactive({ a: 1, b: 2 })
const { a, b } = state // reactive 直接解構 → 失去響應,解構後不是響應式
import { toRefs } from 'vue'
const { a, b } = toRefs(state) // 正確做法:toRefs
ref
、何時用 reactive
count++
、objRef.value = {...}
):ref
reactive
markRaw
或保持非響應在 template 中 {{ count }}
等同 count.value
;但在 JS/TS 中還是要用 .value
。