俺、サービス売って家買うんだ

Swift, Vue.js, 統計, GCP / このペースで作ってればいつか2-3億で売れるのがポっと出来るんじゃなかろうか

Vuexを利用せずに親子関係を持たないコンポーネント同士で通信する

f:id:ie-kau:20150818232251p:plain


しばらくぶりに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のフレームワーク導入を検討するのが良いでしょう。