5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Vue.js】EventBus~親子関係にないコンポーネントのイベントに対してリアクティブな処理を行う~

Last updated at Posted at 2021-04-08

背景

Vueでは、異なるコンポーネント間で通信するために

  1. event emitterを使って、親コンポーネントを介して2つの子コンポーネント間で通信する
  2. $refsで子コンポーネントと通信する

パターンが存在します。
しかし、これらの方法ではコンポーネント階層が深くなった場合

  1. evemt emitterの場合、コード量がおおくなる
  2. $refsの場合、子コンポーネント内でv-forしているコンポーネントに対してのアクセスが難しい

などの問題が発生します。
それを解決してくれるのがEventBusです。

EventBusとは、Vue.jsのインスタンスで、あるコンポーネントでイベントをemitし、emitされたイベントを別のコンポーネントで直接listenして反応することができます。中央または親コンポーネントを経由せずに、コンポーネント間の独立した通信を実現する安全な方法として機能します。一般的にpublish-subscribe approachと呼ばれる方法で実現されます。

事前条件

  • 階層が深い関係にあるコンポーネント間で通信したい

処理

  • EventBusを用いて、あるコンポーネントでイベントをemitし、emitされたイベントを別のコンポーネントで直接listenし反応させる

事後条件

  • あるコンポーネントで発生したイベント時に別のコンポーネントで特定の処理を実行できる

ポイント

  • EventBusのインスタンスを別のファイルとして作成し、データを共有する2つのコンポーネントにインポートする
  • アプリがDOMにマウントされたときにリスニング処理を初期化するために、ライフサイクルフックを使う(created,mounted)

コード例

eventBus.js
import Vue from 'vue'
export default new Vue()
Leftside.vue
<template>
  <div class="left-side">
    <div class="content">
      <div>
        <label for="location"> Location </label>
        <input type="text" name="location" v-model="location" />
      </div>
      <div>
        <label for="caption"> Caption </label>
        <input type="text" name="caption" v-model="caption" />
      </div>
      <input type="submit" v-on:click="sendData" value="Send">
    </div>
  </div>
</template>

<script>
import EventBus from '../eventBus'

export default {
  data () {
    return {
      location: '',
      caption: ''
    }
  },
  methods: {
    sendData () {
      const payload = {
        location: this.location,
        caption: this.caption
      }
      EventBus.$emit('DATA_PUBLISHED', payload)
    }
  }
}
</script>

<style scoped>
.left-side {
  width: 50%;
  height: 500px;
  float: left;
  background-color: #35495e;
}
input[type=submit] {
    width: 100%;
    background-color: #42b883;
    color: white;
    padding: 14px 20px;
    margin: 8px 0;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}
input[type=text], select {
    width: 100%;
    padding: 12px 20px;
    margin: 8px 0;
    display: inline-block;
    border: 1px solid #ccc;
    border-radius: 4px;
    box-sizing: border-box;
}
</style>
Rightside.vue
<template>
  <div class="right-side">
    <div class="content">
      <p> {{ data.location }} </p>
      <p> {{ data.caption }} </p>
    </div>
  </div>
</template>

<script>
import EventBus from '../eventBus'

export default {
  data () {
    return {
      data: {
        location: 'Location placeholder',
        caption: 'Payload placeholder'
      }
    }
  },
  methods: {
    updateData (payload) {
      this.data = payload
    }
  },
  mounted () {
    EventBus.$on('DATA_PUBLISHED', (payload) => {
      this.updateData(payload)
    })
  }
}
</script>

<style scoped>
.right-side {
  width: 50%;
  height: 500px;
  float: right;
  background-color: #42b883;
  border: 1px;
  border-color: black;
}
</style>

on()メソッドは、EventBus上のイベントをリッスンするために使用されます。このメソッドは2つのパラメータを受け取ります。1つ目はイベント名、2つ目はコールバックメソッドです。
DATA_PUBLISHEDは、publisherが発行し、subscriber が購読するイベントを識別するためのイベント名です。
実は、この他にもoff()once()というメソッドがあります。off()はsubscribeしたイベントを削除するのに使い、once()はイベントをsubscribeするが一度しかトリガーされない場合に使います。購読者がトリガーされた後、購読は解除されます。詳細については、こちらの公式ドキュメントをご覧ください。
EventBusとしてのVueを使って行ったもう一つのクールなことは、サービスからのフェッチによってデータをリロードするために別のコンポーネントをトリガーすることです。データを更新するためにすべてのページをリロードする必要はなく、コンポーネント自体が行います。

参考・引用

https://blog.logrocket.com/using-event-bus-in-vue-js-to-pass-data-between-components/
https://medium.com/easyread/vue-as-event-bus-life-is-happier-7a04fe5231e1

5
2
0

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
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?