Skip to content
⚠️ This article was written in 2018. Some content may be outdated.

Vueイベントバス:コンポーネント間通信

Vueのコンポーネント通信には親子通信(props/emit)とVuex(グローバル状態)という2つの主要な方法に加えて、軽量な方法としてイベントバス(Event Bus)があります。兄弟コンポーネント間や階層をまたいだシンプルな通信に適しています。

イベントバスの作成

javascript
// src/utils/eventBus.js
import Vue from "vue";
export const EventBus = new Vue();

またはVueのプロトタイプに付ける方法もあります:

javascript
// main.js
import Vue from "vue";
Vue.prototype.$bus = new Vue();

基本的な使い方

javascript
// コンポーネントA:イベントを送信
import { EventBus } from '@/utils/eventBus'

export default {
  methods: {
    handleLogin(user) {
      EventBus.$emit('user:login', user)
    }
  }
}

// コンポーネントB:イベントを監視
import { EventBus } from '@/utils/eventBus'

export default {
  created() {
    EventBus.$on('user:login', this.handleUserLogin)
  },
  beforeDestroy() {
    // ⚠️ 破棄前に必ずリスナーを解除!解除しないとメモリリーク
    EventBus.$off('user:login', this.handleUserLogin)
  },
  methods: {
    handleUserLogin(user) {
      console.log('ユーザーがログインしました:', user.name)
    }
  }
}

Vue.prototype.$busを使う場合

javascript
// コンポーネントA
this.$bus.$emit("refresh-list");

// コンポーネントB
export default {
  created() {
    this.$bus.$on("refresh-list", this.loadList);
  },
  beforeDestroy() {
    this.$bus.$off("refresh-list", this.loadList);
  },
};

注意事項

必ずbeforeDestroyで$offを呼ぶこと:

javascript
// ❌ $onのみで$offなし:コンポーネント破棄後もリスナーが残る
// そのコンポーネントに再入すると2つ目のリスナーが登録され、2回発火する
// 何度も行き来すると何度も発火し、メモリリークにもなる

// ✅ セットで使う
created() {
  this.$bus.$on('event', this.handler)
},
beforeDestroy() {
  this.$bus.$off('event', this.handler)
  // 注意:関数の参照を渡す必要がある。無名関数は使えない
  // 下記は$offが効かない:
  // this.$bus.$off('event', () => this.handler()) ← 同じ関数ではない
}

イベントバスとVuexの選択

イベントバスが適している場合:
  - 2〜3コンポーネント間のシンプルな通信
  - 永続化不要の1回限りの通知
  - 素早いプロトタイプ開発

Vuexが適している場合:
  - 複数コンポーネントで共有する状態
  - タイムトラベルデバッグが必要
  - 状態の永続化が必要
  - チーム開発で明確なデータフローが必要

イベントバスを通るイベントがどんどん増えていくなら、Vuexへの移行を検討する時期です。

まとめ

  • イベントバスは本質的に空のVueインスタンスで、イベントのパブリッシュ/サブスクライブに使用
  • $emitで送信、$onで監視、$offで解除
  • コンポーネント破棄時は必ず$offを呼ぶ。呼ばないとメモリリーク
  • シンプルなコンポーネント間通信に適している。複雑なケースはVuexを使用

MIT Licensed