toRef と toRefs
似た名前の toRef と toRefs の違いについて調べる。
❓ toRef について
toRef は、引数として与えられた値から ref を作成します。
例えば、props として受け取った値を変更したい場合があると思います。
props は、一方向のバインディングを形成します。
親コンポーネントで値が変更した場合、子コンポーネントで受け取った props の値は変更されますが、子コンポーネントで受け取った props の値をを変更することはできません。
次のコードはボタンをクリックしても値が変更されません。
<script setup lang="ts">
defineProps<{ count: number }>();
</script>
<template>
<button type="button" @click="count++">count is {{ count }}</button>
</template>
このような場合に toRef を使用することで受け取った props の値を変更することができます。
toRef を使用することで受け取った props から ref を作成することでボタンをクリックした際に値が変更されるようになります。
<script setup lang="ts">
import { toRef } from "vue";
const props = defineProps<{ count: number }>();
const count = toRef(props.count);
</script>
<template>
<button type="button" @click="count++">count is {{ count }}</button>
</template>
この時、toRef は新たに ref を定義するため、親で保持する値が変更されないことに注意してください。
次の親コンポーネントで定義された count の値は変更されません。
<script setup lang="ts">
import { ref } from "vue";
import Child from "./components/Child.vue";
const count = ref<number>(0);
</script>
<template>
<Child :count="count" />
<p>count is {{ count }}</p>
</template>
また、readonly なリアクティブデータとして定義することもできます。
次のコードは先ほどとは異なり、ボタンをクリックしても count の値が変更されることはありません。
<script setup lang="ts">
import { toRef } from "vue";
const props = defineProps<{ count: number }>();
const count = toRef(() => props.count);
</script>
<template>
<button type="button" @click="count++">count is {{ count }}</button>
</template>
❓ toRefs について
toRefs は、reactive によって宣言されたリアクティブなオブジェクトの各プロパティを toRef によって ref に変換します。
<script setup lang="ts">
import { reactive, toRefs } from "vue";
const man = reactive({
age: 20,
});
const stateAsRefs = toRefs(man);
man.age++;
console.log(man.age); // 21
console.log(stateAsRefs.age.value); // 21
stateAsRefs.age.value++;
console.log(man.age); // 22
console.log(stateAsRefs.age.value); // 22
</script>
リアクティビティを損なうことなく、個々の ref を生成することができるため、どちらかの値が変更されるともう片方の値も書き変わります。
toRefs を使用して ref を生成する場合、.value を使用してアクセスする必要があることに注意してください。
✅ まとめ
toRef は引数から ref を生成し、toRefs はリアクティブなオブジェクトから toRef を使用して個別の ref を生成します。