Vue3における親子間のデータ渡しとイベントの仕組み

親から子へのデータ渡し

v-model を使用したデータのバインディング

Vue 3 では、v-model を使用して親コンポーネントから子コンポーネントにデータを渡し、双方向データバインディングを実現できます。デフォルトでは v-modelmodelValue を渡しますが、カスタムプロパティ名を使用することも可能です。

親コンポーネントの例

<template>
  <ConfirmDeleteDialog v-model:visible="dialog" @confirm="goToCustomerDelete" />
</template>

<script setup>
import { ref } from 'vue';

const dialog = ref(false);

const goToCustomerDelete = () => {
  console.log("削除を実行しました。");
};
</script>

上記では、dialog という親コンポーネントのデータが子コンポーネントに渡され、さらに子コンポーネントがデータを更新することで親の状態も変更されます。

子コンポーネントの例

<script setup lang="ts">
import { ref, watch } from 'vue';

interface Props {
  visible: boolean;
}

const props = defineProps<Props>();

const emit = defineEmits<{
  (event: "update:visible", value: boolean): void;
  (event: "confirm"): void;
}>();

const localVisible = ref(props.visible);

watch(() => props.visible, (newVal) => {
  localVisible.value = newVal;
});

const closeDialog = () => {
  emit("update:visible", false);
};

const confirmDelete = () => {
  emit("confirm");
  closeDialog();
};
</script>

<template>
  <v-dialog v-model="localVisible" max-width="400px">
    <v-card>
      <v-card-title class="text-h6">本当に削除しますか?</v-card-title>
      <v-card-text>この操作は元に戻せません。</v-card-text>
      <v-card-actions>
        <v-spacer></v-spacer>
        <v-btn @click="closeDialog">キャンセル</v-btn>
        <v-btn color="red-darken-1" class="text-none" variant="flat" @click="confirmDelete">削除</v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>

解説

  1. props によるデータ受け取り
    • 親コンポーネントから渡された dialog は、props.visible として受け取ります。
  2. emit によるデータ更新
    • 子コンポーネントで emit("update:visible", 値) を発火することで、親コンポーネントのデータを更新します。
  3. ローカル状態の管理
    • localVisible を使用してローカルの状態を管理し、watchprops.visible の変更を反映しています。

子から親へのデータ送信

update:<プロパティ名> のイベント

v-model を使用する場合、子コンポーネントは update:<プロパティ名> イベントを発火させる必要があります。これにより、親コンポーネントのデータが更新されます。

親コンポーネント

<ConfirmDeleteDialog v-model:visible="dialog" @confirm="goToCustomerDelete" />

子コンポーネント

const emit = defineEmits<{
  (event: "update:visible", value: boolean): void;
  (event: "confirm"): void;
}>();

const closeDialog = () => {
  emit("update:visible", false);
};

defineEmits とイベントの型定義

defineEmits は、子コンポーネントから親コンポーネントへイベントを通知するために使用します。TypeScript を使用する場合、イベント名や引数の型を明示的に定義できます。

型定義の例

const emit = defineEmits<{
  (event: "update:visible", value: boolean): void;
  (event: "confirm"): void;
}>();

解説

  1. (event: "update:visible", value: boolean): void;
    • update:visible イベントには、boolean 型の引数 value を渡す必要があることを示しています。
  2. (event: "confirm"): void;
    • confirm イベントは引数を必要としないことを示しています。

イベントの発火例

emit("update:visible", true);  // `update:visible` を発火し、true を渡す
emit("confirm");               // `confirm` を発火する

まとめ

  • 親から子へデータを渡す際は、props を使用します。
  • 親から子への双方向バインディングには、v-modelupdate:<プロパティ名> を組み合わせます。
  • 子から親への通知は、emit を使用します。
  • defineEmits を用いることで、イベントの型を明示的に定義し、コードの可読性と安全性を向上させます。