【Vuetify】v-selectで使えるpropsやeventを理解する

Vuetifyのv-selectコンポーネントを使っていましたが、@changeイベントが発火されずハマったので備忘録としてまとめます。

バージョン
  • Vue.js 3.3.4
  • Vuetify 3.4.4
目次

問題

私の職場では「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"と書くとエラーになってしまいます。

そこで以下の実装を施しました。

  1. SamplePresentation.vue内にlocalSelectedAnimalIdを設ける
  2. v-model="localSelectedAnimalId"とすることでv-selectのvalueとlocalSelectedAnimalIdを連動させる
  3. localSelectedAnimalIdが変更されるたびにwatchプロパティを用いてprops.updateSelectedAnimalIdを実行する
  4. 親コンポーネントのselectedAnimalIdを更新できるようになった!

おわりに

VuetifyのようなUIコンポーネントライブラリを使う際は、そのコンポーネントがどのpropsやeventを受け付けているのか、ドキュメントを見てしっかり確認する必要があると学びました。

参考文献

技術書が好きなエンジニア向け

あわせて読みたい
「技術書の内容が頭に入らない」を防ぐ5つの読書方法 「技術書の内容が頭に入らない」を防ぐための5つの読書方法を紹介します。最後まで読めば効率よくインプットできるようになります。
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

未経験でSESから従業員300名以上の自社開発企業に転職しました。業務や個人開発で直面した問題や、転職・学習の経験を発信していきます。

コメント

コメントする

目次