Vue3で親子コンポーネント間データ送受信

Vue2については「Vue/Vuetify ダイアログの設置と親子コンポーネント間のデータ送受信」で書いたが、Vue3では書き方が違うのでまとめておく。また、子コンポーネントとしてVuetify3(beta)の確認ダイアログを使用して動作を確認しておく。

基本

Vue3における親子コンポーネント間データ受け渡しの仕組み。(<script setup>構文)

親コンポーネントから子コンポーネントへの送受信

親コンポーネントからの送信

親コンポーネントからはプロパティとしてv-bindディレクティブ「:」でデータを渡すことができる。

<child-component :parentProp="parentData">

子コンポーネントでの受信

子コンポーネントはプロパティとしてデータを受信

<script setup>
  …
  const props = defineProps({
    parentProp: String,
  })
  const parentData = ref(props.parentProp)
  …
</script>

子コンポーネントから親コンポーネントへの送受信

子コンポーネントからの送信

子コンポーネントでEmitを定義

emit(親コンポーネントのイベント名, 送信データ)

定義したEmitを実行することで指定した親コンポーネントのイベントが発火

<script setup>
  …
  const emit = defineEmits(['eventEmit'])
  const execEmit = () => {
    emit('eventEmit', { 'response': "Child to Parent" })
  }
  …
</script>

親コンポーネントでの受信

親コンポーネントではv-onディレクティブ「@」で子コンポーネントで定義したEmitのイベントが発火したときのメソッドを定義すると、引数として子コンポーネントで定義したEmitの送信データを受信できる。

<child-component @eventEmit="updateEvent" />

<script setup>
  …
  const childData = ref('')
  const updateEvent = (data) => {
    childData.value = data.response
  }
  …
</script>

親子コンポーネントで同期するならcomputed

<script setup>
  …
  const props = defineProps(['parentProp'])
  const parent = computed(() => {
    return props.parentProp
  })
  …
</script>

確認ダイアログを子コンポーネントとした設定例(<script setup>構文)

Vuetify3(beta)の確認ダイアログを利用した親子コンポーネント間データ送受信で動作を<script setup>構文で確認してみる。

Vue3で親子コンポーネント間データ送受信-確認ダイアログを子コンポーネントとした設定例

開発環境

vue v3.2.40
Vuetify3(Beta)

ファイル構成

components
┣ Share
┃ ┗ Confirm.vue
┗ Test.vue

親コンポーネント

<template>
  <h1>Test</h1>
  <confirm-dialog :confirmText="message" @eventEmit="execEvent"></confirm-dialog>
  <p>{{ response }}</p>
</template>

<script setup>
import { ref } from 'vue'
import ConfirmDialog from './Share/Confirm.vue'
const message = ref("よろしいですか?")

const response = ref("")
const execEvent = (data) => {
  response.value = data.message
}
</script>

子コンポーネント(Dialog)

<template>
  <v-btn
    color="primary"
    @click = "dialog = true"
  >
    確認
  </v-btn>

  <v-dialog
    v-model="dialog"
    max-width="500px"
  >
    <v-card>
      <v-card-text>
        {{ agreement }}
      </v-card-text>
      <v-card-actions>
        <v-btn variant="outlined" @click="dialog = false">Cancel</v-btn>
        <v-btn variant="outlined" color="success" @click="execEmit(true)">OK</v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>

<script setup>
  import { ref } from 'vue'
  const props = defineProps({
    confirmText: String,
  })
  const dialog = ref(false)
  const agreement = props.confirmText

  const emit = defineEmits(['eventEmit'])
  const execEmit = () => {
    emit('eventEmit', { 'result': true, 'message': "確認しました"})
    dialog.value = false
  }
</script>

確認ダイアログを子コンポーネントとした設定例(通常構文)

上記では<script setup>構文で記述しているがVue3通常構文では書き方が異なるので一応記載しておく。

親コンポーネント

<template>
  <h1>Sample</h1>
  <confirm-dialog :confirmText="message" @eventEmit="execEvent"></confirm-dialog>
  <p>{{ response }}</p>
</template>

<script>
import { defineComponent,ref } from 'vue'
import ConfirmDialog from './Share/Confirm2.vue'

export default defineComponent({
  components: {
    ConfirmDialog,
  },
  setup() {
    const message = ref("よろしいですか?")
    const response = ref("")
    const execEvent = (data) => {
      response.value = data.message
    }
    return {
      message,
      response,
      execEvent,
    }
  }
})
</script>

子コンポーネント(Dialog)

<template>
  <v-btn
    color="primary"
    @click = "dialog = true"
  >
    確認
  </v-btn>

  <v-dialog
    v-model="dialog"
    max-width="500px"
  >
    <v-card>
      <v-card-text>
        {{ agreement }}
      </v-card-text>
      <v-card-actions>
        <v-btn variant="outlined" @click="dialog = false">Cancel</v-btn>
        <v-btn variant="outlined" color="success" @click="execEmit(true)">OK</v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>

<script>
  import { ref, defineComponent } from 'vue'
  export default defineComponent({
    props: {
      confirmText: {
        type: String,
      }
    },
    emits: ['eventEmit'],
    setup(props, context) {
      const dialog = ref(false)
      const agreement = props.confirmText
      const execEmit = () => {
        context.emit('eventEmit', { 'result': true, 'message': "確認しました"})
        dialog.value = false
      }
      return {
        dialog,
        agreement,
        execEmit
      }
    }
  })
</script>