【Vue.js】コンポーネント間のデータ通信：props, $emit, refs の使い方



### はじめに

Vue.js でコンポーネント間のデータ通信（特に親子コンポーネント間のやり取り）を行う場合、代表的な方法として `props` と `$emit` を使う方法があります。また特定のケースでは `refs` を使うことも可能です。以下では Vue 2.x を想定し、それぞれの方法がどういった用途で使われるかを解説します。

### 1. 親 → 子 のデータ受け渡し：props

#### 1-1. props とは？
- 親コンポーネント から 子コンポーネント にデータを渡すための仕組み
- 子コンポーネント側で `props` オプションを使って 受け取るデータの型や必須項目かどうか を定義

#### 使い方の基本

**親コンポーネント (Parent.vue)**

```html
<template>
  <div>
    <h1>親コンポーネント</h1>
    <!-- 子コンポーネントに "message" という props を渡している -->
    <ChildComponent :message="parentMessage" />
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  data() {
    return {
      parentMessage: 'Hello from Parent'
    }
  },
  components: {
    ChildComponent
  }
}
</script>
```

**子コンポーネント (ChildComponent.vue)**

```html
<template>
  <div>
    <p>子コンポーネント</p>
    <p>親から渡されたメッセージ: {{ message }}</p>
  </div>
</template>

<script>
export default {
  props: {
    message: {
      type: String,
      required: true
    }
  }
}
</script>
```

- 親は `<ChildComponent :message="parentMessage" />` で props を渡す
- 子は `props` オプションで受け取りを定義して、テンプレート内で `{{ message }}` のように使用

#### ポイント
1. props は親 → 子 の一方向
   - 子コンポーネントは親から受け取った props を直接変更しないことがベストプラクティス
2. 子が受け取るデータの 型検証 や 必須チェック が可能
3. Vue 2.x ではルール上、親から子へ 「一方向のデータフロー」 を保つために props を使う

### 2. 子 → 親 のイベント通知：$emit

#### 2-1. $emit とは？
- 子コンポーネント が 親コンポーネント に対してイベントを発行できる仕組み
- 親は子が発行したイベントを `v-on`（または `@`） で受け取り、データを更新したり処理を実行できる

#### 使い方の基本

**子コンポーネント (ChildComponent.vue)**

```html
<template>
  <div>
    <button @click="notifyParent">子から親へ通知</button>
  </div>
</template>

<script>
export default {
  methods: {
    notifyParent() {
      // "child-click" というイベントを発行
      this.$emit('child-click', 'こんにちは！');
    }
  }
}
</script>
```

- `this.$emit('イベント名', 引数...)` の形式でイベントを発行
- 第2引数以降はイベントリスナーのコールバックに渡される

**親コンポーネント (Parent.vue)**

```html
<template>
  <div>
    <ChildComponent @child-click="handleChildClick" />
    <p>子から受け取ったメッセージ: {{ childMessage }}</p>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  data() {
    return {
      childMessage: ''
    }
  },
  components: { ChildComponent },
  methods: {
    handleChildClick(message) {
      this.childMessage = message;
    }
  }
}
</script>
```

- `@child-click="handleChildClick"` のように、子が発行したイベントをリッスン
- `handleChildClick` の引数 `message` が子コンポーネントから送られたデータ

#### ポイント
1. 子 → 親 の一方向
   - 親のデータを子から直接変更するのではなく、イベントを使って「子が親に通知 → 親が自身の状態を更新」
2. 親子間の状態管理が明確になり、データフローを追いやすい
3. Vue 2.x で「単純な親子通信」をする場合は、props + $emit の組み合わせが基本

### 3. refs を使った直接アクセス

#### 3-1. refs とは？
- 親コンポーネント から 子コンポーネントインスタンス や DOM 要素 を 直接参照 するための機能
- テンプレートで `ref="子に付ける名前"` を指定すると、親の `this.$refs.子の名前` で参照できる
- コンポーネント同士の結合が強くなりやすい ため、通常は `props` / `$emit` を優先する

#### 使い方の基本

**子コンポーネント (ChildComponent.vue)**

```html
<template>
  <div>
    <p>子コンポーネントのメッセージ: {{ childMessage }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      childMessage: 'Default child message'
    }
  },
  methods: {
    updateMessage(newMsg) {
      this.childMessage = newMsg;
    }
  }
}
</script>
```

**親コンポーネント (Parent.vue)**

```html
<template>
  <div>
    <!-- ref="childCmp" をつけると親が子のインスタンスにアクセスできる -->
    <ChildComponent ref="childCmp" />
    <button @click="changeChildMessage">子のメッセージを直接変更</button>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: { ChildComponent },
  methods: {
    changeChildMessage() {
      // $refs.childCmp は ChildComponent のインスタンスを返す
      this.$refs.childCmp.updateMessage("New message from Parent!");
    }
  }
}
</script>
```

- `this.$refs.childCmp` で 子コンポーネントのインスタンス を取得
- そこに定義された methods や data に直接アクセス可能

#### ポイント
1. 柔軟性がある反面、コンポーネント間の結合度が高くなる
   - 子のメソッド名やデータ構造が変わると、親のコードも同時に修正する必要がある
2. 一般的には props + $emit で実現できないときの最終手段、またはライブラリ初期化など特殊な場面で使用
3. DOM 要素への直接アクセス（`<div ref="foo">` のように書いて `this.$refs.foo` で要素を取得）も可能

### 4. まとめ

#### 4-1. 親 → 子：props
- 親が子へデータを渡すときに使う
- **一方向（親 → 子）**のデータフローを保つのが基本
- 子は受け取った props を そのまま表示・使用 する

#### 4-2. 子 → 親：$emit
- 子から親へ、イベントを発行し通知する仕組み
- 親はそのイベントをハンドリングして状態を更新したり処理を行う
- 一方向（子 → 親） へイベントが流れる

#### 4-3. refs
- 親が子コンポーネントを直接参照する方法
- 柔軟だが結合度が高くなるため、多用は避ける
- 一般的には props / $emit では対応しづらいケースや特殊なDOM操作で使う

### 5. 結論

Vue 2.x の基本的な親子通信は「props で親から子へデータを渡し、子から親へは $emit でイベントを通知する」 というパターンがほとんどです。

- メリット: データフローがシンプルで可読性が高い
- デメリット: props と $emit では不可能な特殊な操作の場合は、refs や Vuex・Piniaなどのグローバルストアを検討

まずは props / $emit をマスターし、どうしても必要な場合にのみ refs を使用する、というのが Vue 2.x での一般的な設計方針となります。