2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Vue.js における Props の受け渡しと Emit によるイベント発火の流れ

Posted at

1. はじめに

現在、Vue2 から Vue3 へのマイグレーションに携わる中で、
「そもそも props とは?emits とは?」といった基礎でつまずいてしまいました。
そこで今回は、v-model を使用したモーダルのコード例をもとに、流れを再確認してみようと思います。

本記事では、従来のOptions API で書いたコードを例に紹介します。

ここでは、親子間での props の受け渡しと、子コンポーネントから親コンポーネントへの emit によるイベント発火を、具体的なコード例を通してまとめます。

2. コンポーネントの構成

今回の例は 2 つのコンポーネントから成り立っています。

  • 親コンポーネント
    ボタンをクリックすると visibletrue になり、その状態が子コンポーネントへ渡す

  • 子コンポーネント(モーダル)
    親から渡された visible をもとにモーダルを表示し、モーダル内部でのクローズ操作によって親へ状態変更を通知する

親コンポーネントのコード例

<template>
  <!-- ボタンをクリックすると、visible が true に更新され、子に伝わる -->
  <button @click="visible = true">Open Modal</button>
  <ChildComponent v-model:visible="visible" />
</template>

<script>
export default {
  data() {
    return {
      // モーダルの表示/非表示管理
      visible: false,
    }
  },
}
</script>

子コンポーネントのコード例

<template>
  <div v-if="localVisible" class="modal-overlay">
    <div class="modal-content">
      <p>Modal Content Here</p>
      <!-- クローズボタンでモーダルを閉じる -->
      <button @click="closeModal">Close</button>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    // 親コンポーネントから受け取る状態
    visible: {
      type: Boolean,
      default: false,
    },
  },
  emits: ['update:visible'],
  computed: {
    // computed プロパティで props をラップして双方向データバインディングを実現
    localVisible: {
      get() {
        return this.visible;
      },
      set(value) {
        this.$emit('update:visible', value);
      },
    },
  },
  methods: {
    closeModal() {
      // クローズボタン押下時、親にモーダルを閉じるよう通知
      this.$emit('update:visible', false);
    },
  },
}
</script>

<style scoped>
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5); 
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.modal-content {
  background: #fff;
  padding: 20px;
  border-radius: 4px;
  min-width: 300px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
</style>

3. Props の受け渡し

親から子へのデータ伝達

  • 親コンポーネント側
    data オプションで定義した visible を管理し、ボタンがクリックされると visible の値を true に更新

  • 子コンポーネント側
    props オプションで visible を受け取ることで、親コンポーネントの状態を参照できるようにする

4. v-model を用いた双方向バインディングの実現

computed プロパティでのラッピング

  • 子コンポーネントでは、親のvisibleを直接変更できないため、localVisible という computed プロパティを定義し、以下のように動作させています:
    • Getter:
      親から渡された visible をそのまま返し、表示条件(v-if)などで使用
    • Setter:
      localVisible に値が設定されると、this.$emit('update:visible', value) を実行し、親に変更を通知

こうすることで、<ChildComponent v-model:visible="visible" /> と書いた際に、Vue は内部的に update:visible イベントを監視し、親の visible を更新します。

5. Emit によるイベント発火の流れ

子から親への通知

  • 閉じる操作の場合:
    子コンポーネント内の「Close」ボタンがクリックされると、closeModal メソッドが呼び出され、その中で this.$emit('update:visible', false) を実行します
    これにより、親コンポーネントに対して「モーダルを閉じる」ように通知します

親コンポーネントでの反映

  • 親は v-model:visible を通じて子の update:visible イベントを受け取っているため、false が emit されると自動的に visible が更新され、モーダルが非表示となります

6. まとめ

  • データの一方向伝播:
    親から子へは props を使って一方向に状態(この例では visible)が渡される

  • 子から親への通知:
    子コンポーネントは、$emit でイベント(ここでは update:visible)を発火し、親に状態変更を通知する

  • 双方向バインディングの実現:
    computed プロパティの getter / setter を設定することで、v-model による双方向バインディングが実現

7.参考

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?