Vuexを利用せずに親子関係を持たないコンポーネント同士で通信する
しばらくぶりにWebのフロントエンドを書いてるので色々復習を込めて。
ReactやVueなどコンポーネント指向で実装できるフレームワークを利用して開発する際に親子関係を持たないコンポーネント同士で通信をしたい時ってありますよね。
とりわけシングルページアプリケーションを作っている際に自分がよく出会うケースとして
- 共通ヘッダーのタイトルを書き換える
- ページによって共通ヘッダーに「戻る」ナビゲーションを出したり消したりする
- バックグラウンドで通信し続けているソケットからデータを受信して画面上にNotificationのバッヂやポップアップを出す
とかがあります。
こういう時にこそアプリケーション全体で一つのstoreを共有してstateを管理する方針のfluxパターンを実現するVuexやReduxを導入したくなります。
ただただ、概念を理解したり動くようになるまでに準備が結構必要だったりと、ちょっとした開発や、アプリケーション全体で親子関係を持たないコンポーネント間通信が数回しか無かったりするとやることが多すぎると感じることが多々あります。
で、EventEmitterを継承したクラスを作ってエイヤッ!ってやることも多かったのですが、実はVue.jsのドキュメントを読み込んでみると
親子間以外の通信
たびたび、互いに親子関係ではない2つのコンポーネントが互いに通信する必要があるかもしれません。簡単なシナリオとして、空の Vue インスタンスを中 心のイベントバスとして使用することができます。
とのことで、空のVueインスタンスを使えば $on, $emitで通信できるイベントバスとして利用できると公式で明言されていました。 (イベントバスと言う言葉は知らなかったのですが。)
なのでどんな形でもいいのでアプリケーション上で一つのイベントバスを作ってそれを経由させてイベントのやり取りをするのが良いでしょう。
例えば、全てのコンポーネントの上にポップアップを出してモーダル状態にするとなるとこんなイメージです。
Vue.js | 2.x系 |
---|---|
vue-router | 2.x系 |
EventBus.js
import Vue from 'vue' const EventBus = new Vue() export default EventBus
App.js プアリケーション全体管理のJS
import EventBus from '../libs/EventBus.js' export default { name: 'App', created() { EventBus.$on('show-popup', this.showPopup) EventBus.$on('hide-popup', this.hidePopup) }, data() { return { isPopupShonw: false, isOverlayShown: false } }, methods: { showPopup() { this.isPopupShown = true this.isOverlayShown = true }, hidePopup() { this.isPopupShown = false this.isOverlayShown = false } } }
コンポーネント
<template> <main> <header>ヘッダー</header> // vue-routerを利用した際のコンテンツ <router-view></router-view> <div v-show="isPopupShown" class="popup">ポップアップだよ</div> <div @click='hidePopup' v-show="isOverlayShown"></div> </main> </template>
てな具合でしょうか。
まとめ
こんな感じでイベントを利用したコンポーネント間通信が簡単にできます。
注意としては、やりすぎるとイベント地獄が待っているのでアプリケーショ大きくなり始めたところで、規約を持たせるためFluxのフレームワーク導入を検討するのが良いでしょう。
参考書籍
- 作者: mio
- 出版社/メーカー: シーアンドアール研究所
- 発売日: 2018/05/29
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
- 作者: 川口和也,喜多啓介,野田陽平,手島拓也,片山真也
- 出版社/メーカー: 技術評論社
- 発売日: 2018/09/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る