vue.js
vue-router

Vue.js のグローバルイベントバスでの親子間以外の通信と vue-router

More than 1 year has passed since last update.

vue-router と親子間以外の通信のグローバルイベントバスの組み合わせでは画面遷移しても紐づけたイベントの解除は行われない

解除が行われない、というより .$off をしないと蓄積するようです

お試しページ

codesandbox.ioの Vue.js 用基本テンプレートを使用したこちら

  • vue-router を使用
  • 2 画面の単純な構成でリンクの遷移先はそれぞれ相手同士
    • /hello
    • /good-bye
  • components 配下
    • Hello.vue
    • GoodBye.vue
    • li_a.vue
      Hello, GoodBye それぞれでリンク表示に使用している
  • a タグのリンクは li_a.vue での記載で
    event.preventDefault() により通常の遷移をさせず
    グローバルイベントバスを経由させ親要素にそれぞれ処理をさせている (this.$emit にて通知が可能となるがイベントバスを経由させている)
  • .$on によるイベントの紐づけを .mounted() にて実施
    li_a.vue から .$emit するイベント名は Hello, GoodBye ともに "click_link" として同じにしている

増えていくイベント

上記内容の実装にて

  • hello -> good-bye では単純に遷移し
  • good-bye -> hello では GoodBye での定義内容により
    ダイアログが表示され hello へと戻る

これを繰り返すと

  • hello -> good-bye でのクリックでもダイアログが表示されるようになり
  • good-bye を開くたびにダイアログが表示される回数が増えていく

console.log にて出力している内容でも
EventBus._events.click_link の要素数が遷移に伴い増えているのが確認できる

原因・・・?

vue-router を使用した際にオブジェクトを再利用できるよう
特定のオブジェクトの破棄は行っていないらしい

  • 「特定の」を示す範囲はちょっと調べられてはおりません・・・
  • 根拠自体も何かの英語の記事か GitHub の issue で見たような・・・ぐらいです

グローバルイベントバスのオブジェクトは破棄されず残るオブジェクトのようで
EventBus._events に格納されたイベントの紐づけは明示的に .$off をしないと解除されない模様

考えられる対応

イベント紐づけの前に更地に

残ってしまうのであれば定義前に解除をしてしまえばよいのでは・・・
ということで .$on の実行前に .$off にて紐づけを初期化

$offで初期化してから
  // 紐付きをクリアしてから
  EventBus.$off('click_link');
  // 改めてイベントをセット
  EventBus.$on('click_link', this.click_link);

おかたずけ

Vue インスタンスのライフサイクルに従い
コンポーネントの生成、破棄のタイミングにて紐づけ、解除をそれぞれ実施

mounted,beforeDestroyでのそれぞれ設定
  mounted() {
    // 最初にセット
    EventBus.$on('click_link', this.click_link);
  },
  beforeDestroy() {
    // コンポーネントについては beforeDestroy が実行されるので
    // 最後にクリア
    EventBus.$off('click_link');
  }

Vuex を使用

Vuex とは何か
・・・今のところは本格的に使用していないため感覚はつかめておりません

親子間以外でのグローバルイベントバスを使用したイベント通知などは
Vue.js としては本筋から離れるやりとりであるそうで
根深くなる前に整理しておいたほうがよさそうです