先日『Flux UtilsでのFlux実装方法を超シンプルなサンプルを使って解説』という記事を投稿しました。こちらの記事では、Facebook製のFluxフレームワークであるFlux Utils(facebook/flux)で用意されているユティリティクラスのうちReduceStoreクラスを使ってサンプルを作りました。今回は、Fluxの「state」をイミュータブルなMapとして定義できるMapStoreクラスを使うと、前回のサンプルをどう書き換えることができるか紹介したいと思います。
はじめに
まず、今回の記事で扱うサンプルは以下となります。フォームに入力したテキストを表示させるだけのとても単純なものとなっています。
それから、今回の記事は先日投稿した『Flux UtilsでのFlux実装方法を超シンプルなサンプルを使って解説』を元に書いていくので、事前にこちらの記事も目を通しておいてください。
またFlux Utils(facebook/flux)についての詳細は以下をご参照ください。
- facebook/flux
- Flux | Application Architecture for Building User Interfaces
- Flux Utilsのドキュメント日本語訳 – maesblog
Flux Utilsの「MapStore」クラス
Flux Utilsは、Fluxのフレームワークであり、Fluxを構成する「View」「Action」「Dispatcher」「Store」の4つの部分のうち「Store」と「View」の部分を強化するユーティリティとなります。
その中で「Store」向けユーティリティクラスとして、以下の3つのクラスが用意されています。
- Storeクラス: dispatcherを受け取り、storeのインスタンスの作成と登録を行うベースクラス
- ReduceStoreクラス: stateを作成/保持し、actionをreduceしてstateを更新するクラス(Storeクラスを継承している)
- MapStoreクラス: stateをimmutableなMapとして定義するクラス(ReduceStoreを継承している)
MapStoreクラスは上記の通り、Storeクラス、ReduceStoreクラスを継承し、さらにFluxの「state」をイミュータブルなMapとして定義するための機能を持たせたクラスとなっています。
MapStoreクラスのAPIは以下となります。
イミュータブルとは
イミュータブルとは、「変更不可な」ことを言います。Wikipediaでは以下のように説明されています。
オブジェクト指向プログラミングにおいて、イミュータブル(immutable)なオブジェクトとは、作成後にその状態を変えることのできないオブジェクトのことである。 対義語はミュータブル(mutable)なオブジェクトで、作成後も状態を変えることができる。
MapStoreは、FluxのstateをイミュータブルなMapとして定義するためのクラスとなりますが、このイミュータブルにすることが果たして何に役立つのでしょうか。
FluxやReactでstateをイミュータブルにする意味
FluxやReactでは、stateで状態の管理をし、stateが変更されるとviewを更新するような仕組みとなっています。つまり、stateの値を常に比較する必要があります。stateがイミュータブルになっていると、stateを変更する場合は、そもそも変更ができないので、必ずコピーを作り、そのコピーを変更することとなります。そうすることによって、stateの前後の状態が保証されるので、比較がしやすくなり、その結果も確実なものとなります。
[参考]
- Immutable as React state · facebook/immutable-js Wiki
- 「オブジェクトをイミュータブルにしろ」って言うけど、それってたとえば状態が変わったらオブジェクト作り直すってことでしょ、ちょう非効率じゃん。って思ってたんだけど、 – 猫型の蓄音機は 1 分間に 45 回にゃあと鳴く
例えば、以下のようにイミュータブルなオブジェクトを使わない場合は、一見stateとstate2は別物となると思いますが、同じものとみなされてしまいます。
JavaScriptのオブジェクトは、代入は「参照渡し」となるため、代入先のオブジェクトを変更すると、代入元のオブジェクトも変更されるようになっているからです。
オブジェクトをイミュータブルにしてみると、以下のように確実にオブジェクトの変更を捉えることができるようになります。
つまり、stateがイミュータブルでない場合(ミュータブルな場合)、DispatchされるたびにStore内のreduce()メソッドが実行され、常にデータの更新が行われるようになってしまい、パフォーマンス的にもあまりよろしくありません。
Immutable.jsを使う
MapStoreクラス内でstateをイミュータブルにするには、Immutable.jsを使います。Immutable.jsはFacebook製のイミュータブルなデータを扱うためのJavaScriptライブラリです。Flux Utilsは、dependenciesとしてImmutable.jsに依存しているので、Flux Utilsをインストールすると、Immutable.jsも一緒にインストールされます。
npmのバージョンによっては、flux直下のnode_modulesにインストールされている場合もあります。個別にインストールする場合は以下のコマンドを実行します。
MapStoreクラスを使う場合は、このImmutable.jsも読み込む必要があります。
Immutable.jsの詳細は以下などをご参照ください。
変更箇所は以下の3箇所
MapStoreクラスを実装する際のポイントは以下3点となります。先日投稿した『Flux UtilsでのFlux実装方法を超シンプルなサンプルを使って解説』で紹介したソースコードを元に説明するので、こちらも一度目をお通しください。
モジュールの読み込み部分の変更
モジュールの読み込み部分では、Immutable.jsとflux/utilsからMapStoreクラスを読み込むようにします。
Storeの変更
Storeの変更は、以下の3点となります。
- 作成するStoreのclassの継承元をMapStoreにする
- Imuutable.jsを使って初期stateを作成する
- データの更新時にはImuutable.jsのset()メソッドを使う
ポイントとしては、MapStoreクラスを使うことで、イミュータブルなstateに変更があれば、複製が作成され、stateが置き換わるようになります。
View (Container)の変更
Immutable.jsのget()メソッドを使ってStoreのstateの値を取得し、view側のstateにセットするようにします。
まとめ
簡単ではありますが、MapStoreクラスを実装する方法を紹介してきました。ソースコードの全体はGitHubにアップしているので、こちらも合わせてご確認いただければと思います。
上でも述べた通り、stateをイミュータブルなものにすることで、stateの前後の状態が保証されるようになります。そうすることでstateの前後の比較がしやすくなり、その結果も確実なものとなります。結果として、システム全体のパフォーマンスの向上にもつながっくるのではないでしょうか。
Flux Utilsについて色々見ているところですが、なかなか面白いですね。Facebookの型チェックツールのFlowと組み合わせることで、より堅牢なシステムの開発にも対応するようになったりします。この辺またそのうちまとめたいと思います。
コメント