點燈坊

失くすものさえない今が強くなるチャンスよ

使用 toRefs() 對 Prop 解構

Sam Xiao's Avatar 2024-02-20

由於 Prop 是以 Object 形式呈現,會直覺想用 Object Destructure 將其解構,但這會使得 Prop 喪失 Reactivity,必須透過 toRefs() 再 Destructure。

Version

Vue 3.4.0

toRefs()

computed001

  • Prop 不只提供 component 的初始值,之後外部 state 變動也會影響 component 內部 state

App.vue

<template>
  <div>
    <button @click="onClick">Outer +</button>
    <span>External State: {{ count }}</span>
  </div>
  <MyCounter :initialCount="count" />
</template>

<script setup>
import { ref } from 'vue'
import MyCounter from '@/components/MyCounter.vue'

let count = ref(10)
let onClick = () => count.value++
</script>

Line 2

<div>
  <button @click="onClick">Outer +</button>
  <span>External State: {{ count }}</span>
</div>
  • 外部 state 可不斷遞增

Line 6

<MyCounter :initialCount="count" />
  • 外部 state 透過 initialCount prop 傳進 MyCounter component

MyCounter.vue

<template>
  <div class="box">Internal State: {{ count }}</div>
</template>

<script setup>
import { computed, toRefs } from 'vue'

let props = defineProps({ initialCount: Number })
let { initialCount } = toRefs(props)
let count = computed(() => initialCount.value * 10)
</script>

<style scoped>
.box {
  border-style: solid;
  border-width: 2px;
  border-color: red;
  width: fit-content;
}
</style>

Line 8

let props = defineProps({ initialCount: Number })
let { initialCount } = toRefs(props)
let count = computed(() => initialCount.value * 10)
  • defineProps():定義 initialCount prop
  • toRefs():將 reactive object 轉成一般 Object,但每個 property 都是 ref,如此 Object Destructure 之後才不會喪失 reactivity
  • computed():在 computed() 內讀取 prop 並加工,因為使用了 computed(),所以 count state 與 initialCount prop 有連動性

Conclusion

  • 這是 Vue 3 初學者很容易遇到的地雷,若要對 prop 使用 Object Destructuring 且維持 reactivity,別忘了加上 toRefs()