Vue3 提供了 ref() 跟 reactive() 兩種可供資料與畫面響應的資料類型,當程式或 API 傳來的資料改變時,畫面上的資料也會隨之改變。Vue3 的官方文件尤其推薦用戶使用 ref() 來宣告響應資料。以下整理幾個使用 ref() 時會迷惑的問題與解答,你可以 copy 下方的程式碼,到官方提供的 playground 玩玩看。
Q: ref()能夠接受的資料類型為何?
A: 不同於 reactive() 只能接受物件、陣列與collection類型資料。ref()能夠放入字串、數字、布林值、物件、陣列或 Map 等集合式資料。
Q: ref() 是否為深層響應?
A: ref() 為深層響應,下例中即使嵌套多層物件, ref() 仍然能維持資料與畫面的響應。
<script setup>
import { ref } from 'vue'
const msg=ref({a:'1',b:{c:{d:{e:'hello'}}}})
console.log(msg === myGrandSon)
// true
</script>
<template>
<h1>{{ msg.b.c.d.e }}</h1>
<input v-model="msg.b.c.d.e" />
</template>Q: ref() 被賦予給其他的變數,是否會丟失響應性?
A: ref() 並不會因為被賦予給其他變數,就丟掉了響應性,如同下面的例子,即使 msg 被賦予給 mySon,mySon 再被賦予給 myGrandSon ,包在裡面的物件仍然指向與 msg 相同的 reference,維持資料與畫面的響應。
<script setup>
import { ref } from 'vue'
let msg = ref({a:'1',b:{c:'x'}})
const mySon = msg
const myGrandSon = mySon
</script>
<template>
<input v-model="myGrandSon.b.c" />
<h3>{{myGrandSon.b.c}}</h3>
<h3>{{msg.b.c}}</h3>
</template>Q: 物件的嵌套內放入 ref(),是否還會維持響應?
A: 下面範例中,object 的 id 屬性是一個 ref(),被包在物件中,成為物件屬性會失去了響應性。ref() 必須是頂層屬性,要在物件的最外層才有響應。
<script setup>
import { ref } from 'vue'
const count = ref(0)
const object = { id: ref(1) }
</script>
<template>
{{ count + 1 }}
<!-- 1 -->
{{ object.id + 1 }}
<!-- [object Object]1 -->
</template>- 遇到上面情形要使用解構,如此 id 就能維持響應性。
const { id } = object
{{ id + 1 }}
- 第二個方法是加上 .value:嵌在物件中作為屬性的 ref() 不會自動解包(unwrapped),如下加上.value就可以維持響應性。例如
object.id.value就可以解包,如此就能維持響應。
<template>
{{ object.id.value+1 }}
</template>
