こんにちは、SKAhack です。普段はMERYのWebフロントエンドを主に書いています。
今回はMERYのフロントエンドで採用している jQuery + Flux という構成を紹介してみたいと思います。
なぜReactではなくjQueryか
普通はReact + Fluxで語られることが多いですが、MERYではJavaScriptのソースコードの大半がjQueryに依存しており、簡単にはjQueryを捨てられない状態です。 また、Viewの変更をする2つのライブラリを共存させるのも良くないですし、MERYのサービス特性上、現時点で1画面を頻繁に書き換えるような処理は少ないこと、ReactがサポートしていないIE8など古いブラウザもサポートしているという理由でReactを採用するには至っていません。
Fluxの導入についてはReactと違いほとんど考えることなく導入していました。 Fluxは概念のようなもので、導入についてはアーキテクチャとして適切かという点のみ考えればよかったことと、MERYではBackbone.jsなどのフレームワークを使っていなかったので、新しいアーキテクチャの導入も容易にできました。
Fluxとは
FluxはFacebookが2014年に提唱したアーキテクチャの名前で、Dispatcher(Action)、Store、Viewから構成されます。
データが一方向のみに流れるので、依存関係が明確になり、状態を管理せずに済みます。 詳細は Fluxのドキュメント をみるとわかりますが、なぜ今まで思いつかなかったのかと落ち込むくらい上手く機能します。 これは個人的な感想ですが、Fluxの登場前後には “JavaScriptでもFunctional Reactive Programmingを” という流れがあったのですが、Fluxはオブジェクト指向プログラミング的にそれを解決したと思っています。
前置きが長くなってしまいましたが、今回の記事ではFluxのViewをjQueryで扱うことを紹介したいと思います。
jQueryをViewとして使うために
jQueryを使う場合でもReactのような機構を作ります。具体的には setState で状態が変わるか、親のViewが render を呼び出したタイミングで render を呼ぶようにしてViewをレンダリングします。
また、1つのViewは1つの Element をjQueryオブジェクトとして持ち、このオブジェクトに対して書き換えをします。
実際はあまりjQueryオブジェクトであることに意味はないですが、ブラウザ依存の処理などを吸収してくれるので便利です。
レンダリングするHTMLは mustache, handlebars などテンプレートエンジンを使います。差分更新はできませんが、レンダリング前の状態で一意のViewを作りたいので要件は満たしています。
コードの雰囲気はこんな感じになります。
const $ = require('jquery'); const Handlebars = require('handlebars'); const FooStore = require('../stores/foo'); const BarView = require('./bar'); const _template = require('../templates/foo.html'); const template = Handlebars.compile(_template); class FooView { constructor() { this.$elm = $('<div/>'); this.bar; FooStore.on('change', this.onChange.bind(this)); } render(props) { if (!this.bar) { this.bar = new BarView(); } this.$elm.html(template({ data })); // this.barに渡すdataは書き換え不可な状態にしておくと安全 this.setBarView(this.bar.render({ data })); this.handleEvents(); } ... }
このようにViewをReactのコンポーネントに近い構造にしているので、将来的にReact、もしくは軽量なReactに近い何かに移行しやすくなるかもしれないと考えています。
この構成で気をつけないといけないのは、簡単に子を辿っていけたり、親まで遡ることが出来るところなので、気をつけます。一つのViewの中で閉じた状態をつくれば変なことは起こらないと思います。
また、パフォーマンスについて考える必要が出てきた時は、自力で差分更新をすることになります。なるべくViewを小さく作って差分を考える範囲を狭くすると多少マシになります。これについて考えることが多くなるようならReactに変えるのがいいと思います。
まとめ
React使えるならReact使いましょう
まじめに書くと、Reactが選択できなくてもFluxのようなアーキテクチャの選択はできるので、同じような環境で悩んでいる方の参考になればと思います。