Flux – Dispatcherのドキュメント【日本語訳】と実装のポイント

FluxはFacebookの提唱するクライアントサイドのWebアプリケーション(ユーザーインターフェース)を開発するためのアプリケーションアーキテクチャです。FluxはView、Store、Dispacther、Actionの4つの役割に分けられます。今回その中でもFluxの中心となる「Dispatcher」の部分について理解を深めるために、Fluxのドキュメント内のDispatcherの部分を翻訳してみました。Dispatcherがわかれば、Fluxでの実装についてもそれなりにわかるようになると思うので、拙い訳ですが、ぜひ参考にしてみてください。

はじめに – FluxとDispatcher

flux - logo

Fluxは「クライアントサイドのWebアプリケーション(ユーザーインターフェース)を開発するためのアプリケーションアーキテクチャ」です。MVCやMVVMなどと同類です。Fluxは役割によってViewStoreDispatcherActionの4つの部品にわけられます。それぞれの役割は、よく以下の図によって説明されています。データの流れを一方向性にすることで、ReactによるViewの実装をよりシンプルにすることができます。

flux react.js
Flux

Fluxを使ったアプリケーションを開発する際に、Dispatcherの実装が肝になってきます。言葉で説明するより、以下を見ていただけると、それがよくわかると思います。


これから先は、以下のFluxのドキュメントを日本語に訳したものとなります。

Dispatcher (日本語訳)

Dispatcher is used to broadcast payloads to registered callbacks. This is different from generic pub-sub systems in two ways:

Dispatcherは登録されたコールバックにペイロードを一斉送信するために使われます。これは2つの点において一般的なpub-subシステム(発行/購読システム)と異なります。

  • Callbacks are not subscribed to particular events. Every payload is dispatched to every registered callback.
  • Callbacks can be deferred in whole or part until other callbacks have been executed.
  • コールバックは個々のイベントを購読しない。すべてのペイロードはすべての登録されたコールバックに送られる。
  • コールバックは他のコールバックが実行されるまで、すべてもしくは一部延期されうる。

Check out Dispatcher.js for the source code.

ソースコードを通してDispatcher.jsをチェックしましょう。

API

  • register(function callback): string Registers a callback to be invoked with every dispatched payload. Returns a token that can be used with waitFor().
  • unregister(string id): void Removes a callback based on its token.
  • waitFor(array<string> ids): void Waits for the callbacks specified to be invoked before continuing execution of the current callback. This method should only be used by a callback in response to a dispatched payload.
  • dispatch(object payload): void Dispatches a payload to all registered callbacks.
  • isDispatching(): boolean Is this Dispatcher currently dispatching.
  • register(function callback): string 送信されたすべてのペイロードと一緒に呼び出されるコールバックを登録します。waitFor()メソッドで使われるトークンを返します。
  • unregister(string id): void トークンを元にしてコールバックを削除します。
  • waitFor(array<string> ids): void 連続している現在のコールバックの実行前に呼び出されるように指定されたコールバックを待ち受けます。このメソッドは送信されたペイロードに応じたコールバックによってのみ使われるべきです。
  • dispatch(object payload): void ペイロードをすべての登録されたコールバックに送ります。
  • isDispatching(): boolean このDispatcherが現在送信しているかどうかの状態を示します。

Example – 例

For example, consider this hypothetical flight destination form, which selects a default city when a country is selected:

例えば、これを国が選択されたらデフォルトの都市を選択する仮定の飛行目的地フォームを通して考えてみましょう。

var flightDispatcher = new Dispatcher();

// Keeps track of which country is selected
// どの国が選択されたか記録する
var CountryStore = {country: null};

// Keeps track of which city is selected
// どの都市が選択されたか記録する
var CityStore = {city: null};

// Keeps track of the base flight price of the selected city
// 選択された都市の基本飛行料金を記録する
var FlightPriceStore = {price: null};

When a user changes the selected city, we dispatch the payload:

ユーザーが選択された都市を変更した時、ペイロードをdispatchします。

flightDispatcher.dispatch({
  actionType: 'city-update',
  selectedCity: 'paris'
});

This payload is digested by CityStore:

このペイロードはCityStoreによって読み込まれます。

flightDispatcher.register(function(payload) {
  if (payload.actionType === 'city-update') {
    CityStore.city = payload.selectedCity;
  }
});

When the user selects a country, we dispatch the payload:

ユーザーが国を選択した時、ペイロードをdispatchします。

flightDispatcher.dispatch({
  actionType: 'country-update',
  selectedCountry: 'australia'
});

This payload is digested by both stores:

このペイロードは両方のstoreによって読み込まれます。

CountryStore.dispatchToken = flightDispatcher.register(function(payload) {
  if (payload.actionType === 'country-update') {
    CountryStore.country = payload.selectedCountry;
  }
});

When the callback to update CountryStore is registered, we save a reference to the returned token. Using this token with waitFor(), we can guarantee that CountryStore is updated before the callback that updates CityStore needs to query its data.

CountryStoreをアップデートするためのコールバックが登録された時、返されたトークンに参照をセーブします。このトークンをwaitFor()メソッドに渡すことで、CityStoreをアップデートするコールバックがそのデータを照会する必要が出てくる前に、CountryStoreがアップデートされることを保証することが可能となります。

CityStore.dispatchToken = flightDispatcher.register(function(payload) {
  if (payload.actionType === 'country-update') {
    // `CountryStore.country` may not be updated.
  // `CountryStore.country`はアップデートされないかもしれない
    flightDispatcher.waitFor([CountryStore.dispatchToken]);
    // `CountryStore.country` is now guaranteed to be updated.
  // `CountryStore.country`は今アップデートされることを保証される

    // Select the default city for the new country
  // 新しい国のためのデフォルトの都市を選択する
    CityStore.city = getDefaultCityForCountry(CountryStore.country);
  }
});

The usage of waitFor() can be chained, for example:

以下の例のように、waitFor()メソッドの使用は連鎖されます。

FlightPriceStore.dispatchToken =
  flightDispatcher.register(function(payload) {
    switch (payload.actionType) {
      case 'country-update':
      case 'city-update':
        flightDispatcher.waitFor([CityStore.dispatchToken]);
        FlightPriceStore.price =
          getFlightPriceStore(CountryStore.country, CityStore.city);
        break;
  }
});

The country-update payload will be guaranteed to invoke the stores’ registered callbacks in order: CountryStore, CityStore, then FlightPriceStore.

country-updateペイロードは、storeの登録されたコールバックを CountryStore, CityStore, それからFlightPriceStoreの順で呼び出すことを保証されるようになります。

Dispatcherについてポイント解説

翻訳は以上となります。うまく訳せていない部分もあるかと思うので、Dispatcherについて要点をまとめてみました。

Dispatcher(dispatcher.js)のポイント

  • register()メソッドにコールバック関数をセットすると、トークンが返される。
  • register()メソッドによって返されたトークンは、waitFor()メソッドに引数としてセットして使う。
  • dispatch()メソッドを実行すると、引数にセットされたペイロードが、register()メソッドによって登録されているコールバック関数に送られる(複数あればすべてのコールバック関数に)。
  • dispatch()メソッドを実行すると、すべてのコールバック関数に送られる。イベントを監視してコールバック関数を管理するような仕組みをとっていない。どのコールバック関数を実行させるかは、ペイロード内の値で識別する。
  • register()メソッドで登録されたコールバック関数が複数ある場合、waitFor()メソッドを使って優先順位をコントロールする。
  • コールバック関数AとBがあったとして、Aより先にBを実行したい場合は、Aの関数内でBのトークンをセットしたwaitFor()メソッドを実行させる。Aの実行を待たせて、Bが先に実行されるようになる。

Dispatcher(dispatcher.js)の準備

Fluxは、以下のコマンドでインストールできます。

npm install flux

Dispatcherは、以下のように requireして読み込みます。

var Dispatcher = require('flux').Dispatcher;

Dispatcher(dispatcher.js)を使ったFluxの実装について

上記のポイントを踏まえて、dispatcher.jsを使ったFluxの実装方法を簡単にまとめておきます。

View

  • Reactで実装。
  • onClickなどのイベントによって、Actionを呼び出す。
  • Storeの状態を監視し、状況に応じてsetState()メソッドを使ってViewを更新。

Action

  • dispatch()メソッドの引数にオブジェクトリテラル形式のデーター(ペイロード)をセット(Action Creator)。
  • Storeがアクションを識別できるようにアクションタイプ属性を持たせる。
  • ViewでActionが発生したら、対応するdispatch()メソッドを実行。

Dispatcher

  • dispatch()メソッドが実行されたら、引数にセットされているオブジェクト(ペイロード)をStoreに送信。

Store

  • register()メソッドにコールパック関数を登録。
  • Dispatcherによってペイロードが送られて来たら、登録したすべてのコールバック関数を実行。
  • それぞれのコールバック関数は、ペイロードのアクションタイプ属性を見てアクションに対応すべきか否かを判断。
  • コールパック関数が複数ある場合は、waitFor()メソッドを使って順番を制御。
  • 状況に応じて、イベントを発行し、View(React)に通知。

参考サイト & 書籍

最後にFluxやDispatcherについての理解をより深めるのに参考となるサイトを紹介します。

Fluxについての専門的な書籍はまだ出ていないと思います。そんな中で、今年の7月に出版された『WEB+DB PRESS vol.87』に掲載の伊藤直也さんによるFluxの記事(全9頁)は、これからFluxを勉強する方にとっては貴重な情報源になると思います。React単体のコードからFluxを適用させたコードに変えることによって、Fluxの実装のポイントをわかりやすく説明してくれています。自分もこの記事でFluxの理解を深めることができました。最後に紹介しておきます。(ES2015の記事もあるので、かなりオススメです!)

WEB+DB PRESS Vol.87
  • 『WEB+DB PRESS Vol.87』
  • 著者: 佐藤鉄平(著), 小林明大(著), 石村真吾(著), 坂上卓史(著), 上原誠(著), 他13名
  • 出版社: 技術評論社
  • ページ数: 168ページ
  • 発売日: 2015年7月25日
  • ISBN: 4774173703

コメント一覧

  • 必須

コメント