完全に自分用メモ。
Thinking in Reactというチュートリアルを最小webpack構成で試した:
ishikuro/thinking-in-react-webpack-minimum · GitHub
React + Fluxの自分メモ
Webフロントエンドのプログラミングは、jQueryによる素朴なDOM操作から、AngularJSのような双方向バインディングへ移行してきた。しかしWebがコンポーネント指向に進むに従って、状態の管理が分散しがちであることが問題であった。
そこでFacebookが新世代のパラダイムを提案している。コンポーネント指向、仮想DOM、単方向バインディングなViewライブラリのReactを開発し、Fluxという単方向データフローのアーキテクチャを推奨した。
Fluxはアーキテクチャの名前であり、実装に規定はない。従ってgithubでもFluxアーキテクチャの実装が乱立している。今回はReactと、Flux亜種のひとつであるReduxという組み合わせを、Webpackを使って学習した。
これまで、自分でもAngularJS世代(双方向バインディング世代)のVue.jsで開発をしてきたが、きちんとしたデータフローを作ろうとすると自然とFluxっぽい設計になっていた。最上位VueコンポーネントをRootとして、状態はRootへ集約して、子コンポーネントが拾うユーザアクションは全てRootに伝える。Rootにビジネスロジックを持たせて、そこでデータを編集した状態を子コンポーネントに伝播させていってたりとか。Fluxはそういう手法を明確にレールにした印象。
React
Tutorial
Thinking in React
ファイル構成
webpack.config.js: src/*.jsをコンパイルして, dist/bundle.jsへ配置 dist/ + index.html: bundle.jsをロードするだけ src/ + app.js: reactのimportと、実コードを書く
webpack.config.js
module.exports = { entry: [ './src/app' ], output: { path: 'dist', filename: 'bundle.js' }, module: { loaders: [{ test: /\.js$/, loader: 'babel' }] } };
dist/index.html
<!DOCTYPE html> <html> <head> <title>Thinking in React</title> </head> <body> <script src="bundle.js"></script> </body> </html>
コンパイル方法
$ npm install -g webpack $ npm install --save-dev babel-loader $ npm install --save react $ webpack $ open dist/index.html
以下はThinking in Reactより。箇条書きは意訳でもなく、読書メモ的なもの。
Step 1: UIをコンポーネントに分割して名前をつける
- UI要素を箱で囲っていって、名前をつけていく。それがコンポーネントになる。
- "single responsibility principle" 1つのコンポーネントには1つの責務だけを負わせる。
information architectureに注意。JSONのデータモデルと視覚化されたUIがうまく一致するのが良い構造だ。
FilterableProductTable
- SearchgBar
- ProductTable
- ProductCategoryRow
- ProductRow
- ProductRow
- ...
- ProductCategoryRow
- ProductRow
- ProductRow
- ...
Step 2: Reactで静的なバージョンを作ってみる
- まずはインタラクションが無いバージョンを作ってみる。タイプ量が膨大だが考えることは少ない。
- データモデルを描画を意識する。親コンポーネントから子コンポーネントへのデータフローにはpropsを使う。stateは現段階では使ってはいけない。それが必要になるのはインタラクションを追加するときだけだ。
- 書くときはトップダウンでもボトムアップでも良い。小さいサンプルではトップダウンが楽だ。大きいプロジェクトではボトムアップにしてテストを書く。
- このステップで作ったコードは、データモデルをあらわすコンポーネントライブラリになる。
Step2のコードを入れて、コンパイルしてみる。
Reactはwebpackを使ってbundleしてやるので、
import React from 'react';
を一番上に付け加える。
Step 3: 最小のUI stateを特定する
- インタラクティブにするために、Reactではstateを使ってデータモデルへ変更を伝える。
- DRYに沿って作る。最小のmutable stateを特定する。(富豪的に考える。キャッシュはひとまず考えない)
- 親か流れてくるpropsはstateにはしない
- 時間で変化しないものはstateにしない
- 他のpropsやstateから計算できるものはstateにしない
次のデータ一覧のうち*印をつけたものが今回のstate
- プロダクトのリスト
- *サーチテキスト
- *チェックボックス
- フィルタ後のプロダクト
Step 4: stateがどこに伝播するのか決める
- stateがどれを変更するのか、どれが持つのかを決める。
ProductTableはSearchBarのフィルターを使う。ここでまとめるようなコンポーネントはFilterableProductTableである。よってフィルターテキストやチェックボックスのstateはFilterableProductTableに持たせる。子コンポーネントにはpropsを使って渡す。
Step 5: 子から親へのデータフローの追加
- SearchBarからFilterableProductTableへ変更を伝えるコードを追加する。
- Reactの方法では2wayバインディングよりもコード量は増えるが、明示的で分かりやすい。
- inputタグのvalueは常に親からのpropsを反映している。
- inputタグのvalueに変更があれば、SearchBarのhandleChange()が呼ばれ、その中で、prop.onUserInputというコールバックが呼ばれている。(propsにはコールバックを指定することもできる。)
- このコールバックは親のFilterableProductTableのstateを変更するものである。
Flux(Redux)は次回。