【Vue】親子関係にないビューへのデータの受け渡し。event busとは何か？

ビューファイルを調査している時に、`EventBus`という表記に出会した。Vueの公式ファイルを調査していてもなかなか該当する項目がないので調べてみた。

##EventBusとは？
コンポーネントが**親子関係になくてもイベント情報の受け渡しができる**ようにすること。

EventBusの場合は、`$emit`と`$on`（`$off`）を使って受け渡しを行う。


**（参考）子から親へのデータ受け渡し**
`$emit('イベント名', '渡すデータ')`を使って、親側で`@イベント名='メソッド名'`で受け取る。


<br>
###EventBusを使ったデータの受け渡し
通常、`$emit`を使うときは`this.$emit`として、現在のビューインスタンスを指定するが、EventBusを使う場合は、イベントを渡す用の専用のビューインスタンスを用意する。（インスタンス名は任意）

```js:
//イベントバス専用のインスタンスを生成
const eventBus = new Vue();

//データ送信
eventBus.$emit('イベント名', 渡すデータ);

//受け取り
eventBus.$emit('イベント名', 実行するメソッド);
```

指定したイベント名をeventBusを介して送り、対象のメソッドを実行する。

実際はテンプレートをまたぐことになるため、生成したvueインスタンをプロパティで渡し、`this.プロパティ名.$emit`や`this.プロパティ名.$on`で発火させる。


>例として、vueインスタンスを格納した変数名をeventBusにしている。（指定はない）

###実際の受け渡しの流れ
インスタンスの作り方はいろいろある。
mixins（定義したファイルの記述内容をそのまま読み込む）を使ってインスタンスの受け渡しをした場合。

```js:Vueインスタンスの生成(EventBus.js)
import Vue from "vue"

export default {
  data() {
    return {
      eventBus: new Vue(),
    }
  }
}
```

**▼mixinsでインスタンスを読み込む**

```vue:送信元(SendOrigin.vue)
<template>
  <button @click="onClick">送信</button> 
</template>

<script>
import EventBus from "./EventBus"

export default {
  name: "SendOrigin",
  mixins: [EventBus],
  data() {
    return {
      message: 'hello'
    }
  },
  methods: {
    onClick() {
      this.eventBus.$emit('click-event', this.message)
    }
  }
}
</script>
```

<br>
**▼プロパティで受け取る**
親子関係でないテンプレートを用意する。どこかのテンプレートから、v-bindでvueインスタンスの情報を受け継いできた場合の例。（propsで受け取る）

・`this.プロパティ名.$on('イベント名', 実行するメソッド名)`

```vue:受け取り(ReceiveEvent.vue)
<script>
  export default {
    props: ['eventBus']
    data () {
      return {
        msg: ''
      }
    },
    mounted: {
      //nullチェック
      if(this.eventBus){
        this.eventBus.$on('click-event', this.receiveMessage)
      }
    },
    methods: {
      receiveMessage (message) {
        this.msg = "「${message}」を受信しました"
      }
  }
</script>
```

mounted以外でもwatchでイベントを受け取ることもある。



<br>
##eventBusの注意点
eventBusを使ったデータの受け渡しは、過去のVue公式ドキュメントに記載されていたが、今(2021/3時点)は記載されていない。

現在、公式ページではVuexの利用を推奨している。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/0a1ccc7f-c384-0ddb-2d64-4bb4ae833a1c.png)|
|:--|

https://vuejs.org/v2/style-guide/#Non-flux-state-management-use-with-caution

（`$on`を使った受け渡しはbadと書いてある、、）

＞[Vuex公式 Vuexとは何か？](https://vuex.vuejs.org/ja/)


<br>
##（参考）子から親へのデータの受け渡し
EventBusとの違いを見るため、通常の子から親へのデータ受け渡しを確認。

`this.$emit`でイベント情報の受け渡しを行う。

thisは現在のビューインスタンス（親の中で呼び出しているので親）を表す。

###実例
**▼子テンプレートの設定**

送信ボタンを押すと、`onClick`メソッドが発火する。
$emitで親コンポーネントの`click-event`が発動する。親に送るデータは第２引数に記載。


・`this.$emit('イベント名', 渡すデータ)`

```vue:子テンプレート（child.vue）
<template>
  <button @click="onClick">送信</button> 
</template>

<script>
export default {
  name: 'ChiledVue',
  data() {
    return {
      message: 'hello'
    }
  },
  methods: {
    onClick() {
      this.$emit('click-event', this.message)
    }
  }
}
</script>
```

<br>
**▼親テンプレートの設定**
`@イベント名`で$emitの発火情報を受け取り、指定したメソッドを実行する。

・`@イベント名="メソッド名"`

```vue:親テンプレート
<template>
   <ChiledVue @click-event="receiveMessage">{{msg}}</ChiledVue>
</template>
<script>
  import ChildVue from './ChildVue'
 
  export default {
    components: {
      ChildVue
    },
    data () {
      return {
        msg: ''
      }
    },
    methods: {
      receiveMessage (message) {
        this.msg = "「${message}」を受信しました"
      }
    }
  }
</script>
```

通常、$emit経由で受け取ったデータをメソッドの中で処理して、その結果をビューの中で使う。