Vuetifyのv-select
コンポーネントを使っていましたが、@change
イベントが発火されずハマったので備忘録としてまとめます。
問題
私の職場では「Vue.jsのemitは使わずpropsに更新用の関数を渡す」方針となっています。
具体的には以下のSampleContainer.vue
のように、selectedAnimalId
を更新するためのupdateSelectedAnimalId
関数も子コンポーネントに渡しています。
<script setup lang="ts">
import { reactive, ref } from 'vue';
import SamplePresentation from '../presentation/SamplePresentation.vue';
const animals = reactive([
{ id: 1, name: '犬' },
{ id: 2, name: '猫' },
{ id: 3, name: 'うさぎ'},
{ id: 4, name: 'ハムスター' },
{ id: 5, name: 'モルモット' },
])
// 選択された animals のID
const selectedAnimalId = ref()
// selectedAnimalId を更新するための関数
const updateSelectedAnimalId = (newAnimalId: number) => {
selectedAnimalId.value = newAnimalId
}
</script>
<template>
<v-container>
<SamplePresentation
:animals="animals"
:selected-animal-id="selectedAnimalId"
:update-selected-animal-id="updateSelectedAnimalId"
/>
</v-container>
</template>
子コンポーネントのSamplePresentation.vue
側で、v-select
に@change
イベントを設けました。
これにより選択肢を変更するタイミングでupdateSelectedAnimalId
が実行され、親コンポーネントのselectedAnimalId
を更新できると考えましたが、うまくいきませんでした、、。
<script setup lang="ts">
export type Props = {
animals: { id: number, name: string }[]
selectedAnimalId: number
updateSelectedAnimalId: (newAnimalId: number) => void
};
defineProps<Props>()
</script>
<template>
<v-container>
<v-select
label="好きな動物"
:items="animals.map((animal) => animal.name)"
item-title="name"
item-value="id"
@change="updateSelectedAnimal($event.target.value)"
/>
</v-container>
</template>
解決方法
Vuetifyのv-select
コンポーネントはそもそも@change
イベントを受け付けていないことが原因でした。
代わりにv-model
を使う必要があるようです。
そこで上記のSamplePresentation.vue
を次のように修正しました。
<script setup lang="ts">
import { ref } from 'vue';
import { watch } from 'vue';
export type Props = {
animals: { id: number, name: string }[]
selectedAnimalId: number
updateSelectedAnimalId: (newAnimalId: number) => void
};
const props = defineProps<Props>()
// 以下を追加
const localSelectedAnimalId = ref();
watch(localSelectedAnimalId, () => {
props.updateSelectedAnimalId(localSelectedAnimalId.value);
});
</script>
<template>
<v-container>
<v-select
label="好きな動物"
:items="animals"
item-title="name"
item-value="id"
v-model="localSelectedAnimalId"
/>
</v-container>
</template>
Vue.jsのpropsはコンポーネント側で直接変更できません。
なので親コンポーネントから渡されたselectedAnimalId
を使って直接v-model="selectedAnimalId"
と書くとエラーになってしまいます。
そこで以下の実装を施しました。
SamplePresentation.vue
内にlocalSelectedAnimalId
を設けるv-model="localSelectedAnimalId"
とすることでv-select
のvalueとlocalSelectedAnimalId
を連動させるlocalSelectedAnimalId
が変更されるたびにwatch
プロパティを用いてprops.updateSelectedAnimalId
を実行する- 親コンポーネントの
selectedAnimalId
を更新できるようになった!
おわりに
VuetifyのようなUIコンポーネントライブラリを使う際は、そのコンポーネントがどのpropsやeventを受け付けているのか、ドキュメントを見てしっかり確認する必要があると学びました。
コメント