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 にて紐づけを初期化
// 紐付きをクリアしてから
EventBus.$off('click_link');
// 改めてイベントをセット
EventBus.$on('click_link', this.click_link);
おかたずけ
Vue インスタンスのライフサイクルに従い
コンポーネントの生成、破棄のタイミングにて紐づけ、解除をそれぞれ実施
mounted() {
// 最初にセット
EventBus.$on('click_link', this.click_link);
},
beforeDestroy() {
// コンポーネントについては beforeDestroy が実行されるので
// 最後にクリア
EventBus.$off('click_link');
}
Vuex を使用
Vuex とは何か
・・・今のところは本格的に使用していないため感覚はつかめておりません
親子間以外でのグローバルイベントバスを使用したイベント通知などは
Vue.js としては本筋から離れるやりとりであるそうで
根深くなる前に整理しておいたほうがよさそうです