Upload
voyage-group
View
9.426
Download
0
Embed Size (px)
Citation preview
なぜ私はVue.jsを諦め Flux + Reactに 移行したのか
!社内JavaScript現状確認会
前提となる適用先• 管理画面的なWebアプリケーションのリニューアル
…だったもの(仮)
• REST APIを前提としたSingle Page Applicationもどき
(※すべてが1ページではないけど)
• 機能・画面が多い
• 複雑化することがほぼ確実
Viewへの要求事項• 統一されたスタイルでUIとなるHTMLを生成できる
• なるべく簡単に書けること(含セキュリティリスク回避)
(生DOM・jQueryはあり得ない)
• 業界におけるパラダイムが過渡期のため、
巨大フレームワークに乗っかりたくは無い(交換可能な部品の組み合わせでプレーンに)
• 困ってもなんとか出来るための緊急ハッチも必要
まずFluxを採用した話
What is Flux?
It’s not any framework, is just an architecture.
Flux アーキテクチャ• Facebook提唱のGUIアプリのアーキテクチャ
• オブザーバパターンを用いる
• データの流れる方向を単一にする
• 特定のライブラリに依存する思考ではないと解釈している
Fluxのメリット• データの入力と出力のフローが一定になる
• 「あるモジュールに入力が起きた場合、次はどこにデータが来るか?」を規約したアーキテクチャ
• なので、デバッグ的な予測がしやすい
• MVC方言にありがちな概念の言語化
Fluxの辛いところ• 定着した概念ではないので、オレオレFluxが乱立している(情報収集の難)
• 冗長な箇所もある(ほぼ必ずサイクルを一周しなければいけない)
• Store->Viewの通知粒度を細かくしないと、
一般的にViewの更新コストが非常に大きい
何を使ってViewを実装するか?
今回のViewへの要求事項• 統一されたスタイルでUIとなるHTMLを生成できる
• なるべく簡単に書けること(含XSS回避)
• 交換可能な部品の組み合わせでプレーンに.
• 困ってもなんとか出来るための緊急ハッチも必要
(生のDOM APIを触る方法がある)
First, I used Vue.js
※以後のVue体験記は
2014年8~9月初頭の、
v0.10.xの印象である
Vue.js (vuejs.org)
• Model View ViewModel (MVVM) pattern • ES5でデータバインディングする
• Angularのデータバインディングだけ切り出したようなもの
• イケイケJSライブラリの割にドキュメントが文明的
「良い」というよりも「楽」
• 宣言的に書ける • データバインディング
• データを渡せば勝手に表示してくれる • 紐づければ勝手に更新される
• 記述量も少なめ
けれどもな
個人的にイマイチ感あった
• 規約らしいものはあんまりない • 「Vue.jsの考えるViewModel」が言語化されているとは言いがたい
• 特に値と状態の区別が無いのは好きではない(ビュー層の宿命ではあるが)
• Vueのテンプレート定義は複雑な記述が面倒くさい
• 個人的にJSコードとバインド先の記述の分断を感じる • プロトタイプチェーンを書き換える(※最近、改良された)
プロトタイプチェーンを書き換えやがって(^ω^)こういうチェーンがあるじゃろ?
!Hoge | V Hoge.prototype | V Object.prototype
プロトタイプチェーンを書き換えやがって(^ω^)Vue.jsにHogeを渡すじゃろ?
!Vue({ data: { bar: Hoge, }, })
プロトタイプチェーンを書き換えやがって(^ω^)Vue.jsはこう書き換えるじゃろ?
!Hoge | V <Vueの変更監視用プロパティ> | V Object.prototype
プロトタイプチェーンを書き換えやがって(^ω^)Hoge.prototypeは行方不明じゃろ?
!Hoge | V <Vueの変更監視用プロパティ> | V Object.prototype
プロトタイプチェーンを書き換えやがって(^ω^)toString()すらも行方不明じゃろ?
!Hoge | V <Vueの変更監視用プロパティ> | V Object.prototype
※最近のバージョンで prototype残してくれるらしい
結局、Vue.jsは断念
• Backbone.Stickitなどからの移行には有用ではないかと感じる !
• しかし、2014年秋現在、これでゼロから作るかは悩みどころ !
• 生のオブジェクトを扱えないのは悲しい
そうだ、React行こう
React
• View特化ライブラリ(render library)
• 自動差分描画機能を持つ(Virtual DOM)
• データと状態の概念がAPIレベルで 分かれている
• ドキュメントが本当に細かい
(github:facebook/react)
本当のDOMツリー
SyntheticEvent(Virtual Event)
Virtual DOM
差分描画機構React
JSReactのある生活
ユーザー
Virtual DOM
<div> <h1>bar</h1> <p>foo</p> </div>
div
h1 p
bar foo
テンプレートエンジンとして、文字列ではなく木構造を作る
div
h1 p
bar foo
div
h1 p
bar
差分計算の概念図
生成した木構造を中間表現として扱い,データ構造としての比較を行う
本当のDOMツリー
SyntheticEvent(Virtual Event)
Virtual DOM
差分描画機構React
JSデータの表示フロー(概略)
人間
本当のDOMツリー
SyntheticEvent(Virtual Event)
Virtual DOM
差分描画機構React
JSDOMイベントの発生フロー(概略)
人間
Reactのメリット• 実際のDOMの変更処理をReactに丸投げ可能
• 必要なデータを全て一度に入力しても、
自動で差分が計算されるので、常にある程度の速度で描画が可能
• 「参照透過性のあるビュー層」を実現する
Reactのテンプレートの書き方• JSで React.DOM.Div() みたいな関数を使って頑張って組む
• またはJSX (JavaScript XML)で組む
• XMLリテラルぽいが、最終的にプレーンなJSの関数に落とし込まれる
JSX Example (変換前)
JSX Example (変換後)
ReactとFlux
• Store->Viewへの変更通知を簡略化できる
• Reactでは変更後のデータ一式全てを受けても描画コストを抑えられる
• 他ライブラリでは、丁寧に差分情報を作る必要が有る
Reactのテスト• 公式には「これを使え」というモノは無い
• ただしJest(読み込んだものを全部モックにする)というものを公式が超pushしてる
Reactのデメリット• React自身が未だ0.xの状態(バージョンアップ時に破壊的変更の可能性)
• 枯れてはいない
• React管理下のDOMツリーに対して、他のライブラリを当てるのは面倒くさそう
なぜReactに飛び移ったのか
色々あった
Reactを選んだ理由• 参照透過性のあるビュー = 状態予測可能性が高い
• APIレベルでデータの値と状態を分離している
• JSXテンプレートがプログラマブル (積極的に使いたくは無いけど)
• ドキュメントが良い
(開発元のFacebook自身が使ってる)
ReactでFluxを実践した現状
1. Store -> Viewの更新通知• オリジナル
通知を受けたらStoreから、getterメソッドで取得してる
• 弊プロジェクト「そんなことはしない。通知時に一緒にデータ全部を渡す. StoreとViewを疎に.」
2. Actionの更新通知• オリジナル
リクエスト失敗ケースを考えると、APIリクエストもAction起因に
• 弊プロジェクト
APIリクエストはStoreの領分なのと、 サーバーは永続ストレージという認識なので、Storeに詰め込んだ
3. テスト• オリジナル
「Jestでモックすれば楽!」
• 弊プロジェクト
「モックは実装に立ち入り過ぎ. 静的にできる範囲で, mochaとpower-assertで.」
4. Viewのテスト• イベントハンドラの無いViewにユニットテストは必要ないと判断
• イベントハンドラのテストはしたい
• E2Eテストでカバーも考えたい
• ほとんどが未着手・検討中
まとめ• 常に気をつけてMVCをやりたくはなかった
→Fluxを採用した
• Viewの更新を楽にしたいし,
デバッグもなるべく楽にしたかった→Reactを採用した
• ReactはView操作のパラダイムシフト
会場でのQ&Aとか議論とかまとめ
Q. Store内部の依存関係の解決は?
• Dispatcherが処理順序解決の方法を持っているのでそれに頼る(実装依存)
• 無かったらメッセージの種類を増やして頑張るしかなさそう
Q. ユーザーの入力が複数起きたら?
• Fluxの本義に従えば、毎回データフローを回るべきだし、それで十分に回ると思う
• 万が一回らなくなったら、そのとき考える
Q. 「5件メッセージがキューに溜まったら更新したい」場合は、どうする?
• Store側で適切に閾値を決めて、Viewへの通知回数を管理すれば良いのでは
Q. jQueryプラグインなどと併せて使いたい(React移行中のケースなど)
•その話は止めろ
Q. どうしてもjQueryプラグインなどと併せて使いたい
•そんな事を考えてはいけない
Q. やっぱりjQueryプラグインなどと併せて使いたい•本当にそのjQueryプラグインが必要なのか胸に手を当てて考え直して、やっぱり必要だったらReactで書き直すしかない
Q. Reactに書き直している暇はないんだけど、止むに止まれぬビジネス上の緊急を要する都合により早急にこのjQueryプラグインを使わなければ死人が出る可能性も十分にありえる状況において、どうにかしてReactによって統治されたサブツリー内でjQueryプラグインを使う方法はありますか?
• getDOMNode()で生のDOMに触れる + shouldComponentUpdate()を応用して, jQuery適用対象のDOMをReactに更新させなければ、なんとかいける、はず(やったことないので根拠はない)
Q. アニメーションとかどうする?
• ReactがReactCSSTransitionGroupというものを持っているので、これで対応できるはず
• メチャクチャ複雑なことやりたい場合については、まだ体験した事が無いのでよくわからん
• 「絶対に更新されないComponent」を作ればいいんじゃないの?
Q. JSXの名前解決とか
• 普通のJSの関数呼び出しに変換されるので、普通のJSと一緒と考えて良い
• React Componentのメンバ関数のthisは,
各インスタンスにbindされる
Q. Virtual DOMの差分情報は取れる?• ReactにPublicなAPIとしては現在存在しない
• 欲しければ, Matt-Esch/virtual-domを使おう
Q. サーバーサイドでプリレンダリングしたものにReact当て込みたい
• やったことがないのでわからない
• API的には出来そうに思えるけど???
Q. Reactの差分描画は最速?
• DOM職人には勝てないと思う
• 職人エンジニアだけでチームを組まずとも、生産性を維持しつつ「けっこう速い」ものを開発するためのツールと割り切るべきでは