2016.07.20

React.jsアプリケーションのFluxアーキテクチャを調べてみた


最近、関わったプロジェクトがReactを使っていますが、自分は今回Reactをはじめて使うので、Reactを用いたアプリケーションアーキテクチャFluxを調査してみました。今回の記事で、Fluxアーキテクチャと実際の実装について調べた内容を書きたいと思います。

Fluxとは


Reactを用いたアプリケーションアーキテクチャ
Facebookが提唱したSmalltalk MVCの焼き直し
データが一方通行へ流れるようにするアーキテクチャ
ウェブUIについてそれを適応する


Fluxをインストールすればレールに乗れる


調査するため、自分のCentos7サーバに以下の手順でFacebookのTodoMvcアプリケーションの開発環境を構築しました。

ソースコード

https://github.com/facebook/flux

NodeJsのインストール

$ sudo yum install epel-release
$ sudo yum install nodejs
$ node -v
ついでにnpmをインストールするのであれば
$ yum install -y npm --enablerepo=epel
GithubからCloneしたソースコードの直下に以下のコマンドを実行することで(package.jsonに定義される)必要なライブラリを全部インストールできます。とても便利です。
# npm install

早速、Reactアプリケーションをスタートします
# npm start

> todomvc-flux@0.0.3 start /var/www/html/todomvc
> watchify -o js/bundle.js -v -d js/app.js

2906788 bytes written to js/bundle.js (2.42 seconds)
アプリケーションにアクセスしてみると、Todo管理アプリがちゃんと動いていることを確認できました。
Flux_todo_app

ここで、アプリケーションの開発環境構築が完了しました。ソースコードを調査しながらFluxのアーキテクチャーを確認します

Fluxアーキテクチャ


以下はFacebookがFluxの一方通行へ流れるについて説明する図です
flux-overview

実際のソース構成を確認しますと、Action、Store、Component(React)の3つが存在し、それを繋ぐのがEventEmitter(or Dispatcher)です。StoreはActionを監視し、Actionが持つEventEmitterを監視します。ComponentはActionを呼び、ActionがEventを発行します。ComponentはStoreの変更を監視し、Store自身がEventEmitterとして動くイメージです。
todo_app_structure life-cycle

概念
説明
備考
EventEmitter
イベントリスナの登録/処理ができるモジュールを作る。Flux内のイベントも全てディスパッチャから一方向に流れる。
#on : イベントtypeに対してコールバックの登録
#emit: イベントtypeに登録されたコールバックの実装
#off : イベントtypeに対してコールバックの登録解除
ディスパッチャ(Dispatcher)
アプリの中央のハブで、全てのデータの流れを管理する
Store内のデータを操作する処理を行い、その後で 関連するViewのステータスを更新する処理を実行(イベントの発火)する
ストア(Store)
EventEmitterを継承する。あるイベントがやってきたら、State(内部の状態)を更新し、
内部Stateを更新したら”CHANGE”イベントを発行する
MVCのモデルと同じ。
アクション(Action)
あるイベントを発行する関数。アプリケーションに広げるために、イベントをディスパッチャへと送る
Actionには “actionType”プロパティを持たせて、区別できるようにする
Component
・Storeの変更を監視する(Listen)
・Viewの更新
 必要なデータを全て手に入れてしまえば、画面に表示する
・ユーザーイベントの受付
 Clickされた◯◯するといった動作



Todoの更新機能でFluxの実装を確認する

Todo一覧画面にて、ユーザーがTodoを更新すると、TodoActionsのupdateTextを実行する

  input =
        <TodoTextInput
          className="edit"
          onSave={this._onSave}  <---★イベントの設定
          value={todo.text}
        />;

  /**
   * Event handler called within TodoTextInput.
   * Defining this here allows TodoTextInput to be used in multiple places
   * in different ways.
   * @param  {string} text
   */
  _onSave: function(text) {
    TodoActions.updateText(this.props.todo.id, text); <--アクションを呼ぶ
    this.setState({isEditing: false});
  },

TodoActionにてTodoStoreに更新イベントを通知

  var TodoActions = {
  /**
   * @param  {string} id The ID of the ToDo item
   * @param  {string} text
   */
  updateText: function(id, text) {
    AppDispatcher.dispatch({
      actionType: TodoConstants.TODO_UPDATE_TEXT,   <---TodoStoreのほうにDispatch
      id: id,
      text: text
    });
  },

}

TodoStoreのほうは、データ更新し、ビューを更新するため、Componentに通知する

 case TodoConstants.TODO_UPDATE_TEXT:
      text = action.text.trim();
      if (text !== '') {
        update(action.id, {text: text}); <---データストアを更新
        TodoStore.emitChange();           <---Todo画面にデータを更新するため、TodoAppのほうに通知
      }
      break;

TodoApp ComponentがTodoStoreからさ最新データを取得し、ビューを更新する

  var TodoApp = React.createClass({
  componentDidMount: function() {
    TodoStore.addChangeListener(this._onChange);  <--- TodoStoreの変更をListen
  },

  /**
   * 画面表示処理
   * @return {object}
   */
  render: function() {
    return (
      <div>
        <Header />
        <MainSection
          allTodos={this.state.allTodos}
          areAllComplete={this.state.areAllComplete}
        />
        <Footer allTodos={this.state.allTodos} />
      </div>
    );
  },

  /**
   * Event handler for 'change' events coming from the TodoStore
   */
  _onChange: function() {
    this.setState(getTodoState()); <--- 変更があるときは、TodoStoreから全件を取得する
  }

 /**
  * Retrieve the current TODO data from the TodoStore
  */
 function getTodoState() {
   return {
     allTodos: TodoStore.getAll(),
     areAllComplete: TodoStore.areAllComplete()
   };
 }

APIの実行はどこで実装するのか

FluxアーキテクチャでAction CreatorsでAPIを実行しますが、ビューがStoreから最新データを取得するので、APIの実行はStore内から通信してStoreで完結しても良いと思われます。

まとめ

いかがでしょうか?Reactを用いたアプリケーションアーキテクチャFluxについて調査しました。Fluxアーキテクチャにいろいろな要素がありますが、実際のソースコードを確認したらすごくデータの流れなども把握しやすく見通しの良いコードになるかと思います。

参考

https://facebook.github.io/flux/docs/overview.html
http://www.pupha.net/archives/3218/
http://azu.github.io/slide/react-meetup/flux.html

次世代システム研究室では、グループ全体のインテグレーションを支援してくれるアーキテクトを募集しています。アプリケーション開発の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。

皆さんのご応募をお待ちしています。