13. Thinking in React - accgetter/React GitHub Wiki
私たちの考えでは、ReactはJavaScriptを使って大規模で高速なWebアプリケーションを構築するための最も優れた方法です。
それはFacebookとInstagramでとてもにうまくスケーリングされています。
Reactのたくさんある素晴らしいパーツの1つは、アプリの構築について考えさせてくれます。
このドキュメントでは、
Reactを使用して検索可能な製品データテーブルを構築するという考え方を通して説明をしていきます。
すでにJSON APIとデザイナーが作成したモックを持っているとします。モックは次のようになります:
JSON APIは、次のようなデータを返します:
[
{category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"},
{category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"},
{category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"},
{category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"},
{category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"},
{category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"}
];
最初にやりたいことは、モック内のすべてのコンポーネント(およびサブコンポーネント)の周りにボックスを描き、
すべての名前を付けることです。デザイナーがいるなら彼らに相談しましょうー。
彼らのPhotoshopレイヤー名はあなたのReactコンポーネントの名前と同じにしたほうがいいかもしれません。
しかし、どのようにしてコンポーネントを組み立てていくべきか?
新しい機能やオブジェクトを作成する必要があるかどうかを判断するために、
技術を統一しましょう。その手法の1つが単一責任原理です。
つまり、コンポーネントは理想的には実行することは1つである必要があります。
それができたら、より小さなサブコンポーネントに分解されるべきです。
JSONデータモデルをユーザーに表示することが多いため、モデルが正しく構築されていれば、
UI(つまりコンポーネントの構造)もうまくマッピングされます。
これは、UIとデータモデルが同じ情報アーキテクチャを資源とする必要があるためです。
つまり、UIをコンポーネントに分割する作業は結構簡単です。
データモデルの1ピースごとにコンポーネントに分解してください。
アプリケーションに5つのコンポーネントがあることがわかります。
各コンポーネントが表すデータをイタリック体にしました
-
FilterableProductTable
(オレンジ): 全体を含んでいる -
SearchBar
(青): ユーザの入力を受ける -
ProductTable
(緑): ユーザー入力に基づいてデータを表示、フィルタリングします -
ProductCategoryRow
(ターコイズ): 各カテゴリの見出しを表示する -
ProductRow
(赤): それぞれの製品の行を表示する
ProductTable
を見ると、テーブルヘッダ(" Name "と" Price "ラベルを含む)が
独自のコンポーネントではないことがわかります。これは好みの問題であり、
どちらかの方法で行われる議論があります。この例では、 ProductTable
の責任である* データ *のレンダリングの一部であるため、
これを ProductTable
の一部として残しました。
ただし、このヘッダーが複雑になると(例えば、ソート用の情報を追加する場合)、
これを独自の「ProductTableHeader」コンポーネントにすべきです。
モックの中のコンポーネントを特定したので、それらを階層に配置しましょう。
これは簡単です。モック内の別のコンポーネント内に表示されるコンポーネントは、階層内の子として表示されます。
-
FilterableProductTable
SearchBar
-
ProductTable
ProductCategoryRow
ProductRow
See the Pen Thinking In React: Step 2 on CodePen.
これでコンポーネント階層が完成しましたので、今度はアプリを実装しましょう。
一番簡単な方法は、データモデルを取り込んでUIをレンダリングしつつ、
インタラクティブ性を持たないバージョンを作成することです。
静的バージョンを構築するには思考は不要で多くのタイプが必要であり、
インタラクティブ性を追加するには多くの思考が必要であり、
多くのタイピングを必要としないため、
これらのプロセスを切り離すのが最善です。理由はこうです。
データモデルをレンダリングするアプリケーションの静的バージョンを構築するには、
他のコンポーネントを再利用し、* props を使用してデータを渡すコンポーネントを構築したいと思うでしょう。
propは、親から子へデータを渡す方法なので。 state *の概念に精通している場合、
静的なバージョンを構築するためにすこしでもstateは使用してはいけません。
stateは、インタラクティブ機能、つまり時間の経過と共に変化するデータに対してのみと限定されています。
これはアプリの静的なバージョンなので、あなたはstateを使ってはいけません。
トップダウンまたはボトムアップで構築できます。つまり、コンポーネントを階層の上位に構築することから始めます
(つまり、「FilterableProductTable」で始まる)、
もしくはそれよりも下位のコンポーネント(「ProductRow」)を使用してコンポーネントを構築することができます。
簡単な例では、通常、トップダウンのほうが楽です。
大規模なプロジェクトでは、ビルド時にボトムアップしてテストを書く方が簡単です。
このステップの最後にデータモデルをレンダリングする再利用可能なコンポーネントのライブラリが用意されています。
これはアプリケーションの静的なバージョンなので、コンポーネントは render()
メソッドしか持ちません。
階層の最上位にあるコンポーネント( FilterableProductTable
)は、データモデルをpropとして取ります。
基礎となるデータモデルを変更し、 ReactDOM.render()
をもう一度呼び出すと、UIが更新されます。
UIがどのように更新され、どの部分が変わるかは簡単にわかります。複雑なことは何もないからです。
Reactの片方向データフロー(片方向バインディングとも呼ばれます)は、すべてのモジュール化と高速化を実現します。
この手順を実行する際にヘルプが必要な場合は、React docs を参照してください。
Reactには2種類の "モデル" データがあります: propとstateです。両者の違いを理解することは重要です。
その違いがわからない場合は、ざっと[the official React docs](https://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html)を読んでね。
インタラクティブなUIを作成するには、基礎となるデータモデルの変更をトリガできる必要があります。
Reactは** state **でこれを簡単にします。
アプリケーションを正しく構築するには、まずアプリケーションに必要な一連の変更を最小限で考える必要があります。
その鍵はDRY原則です: Don't Repeat Yourself。
アプリケーションが必要とするstateを絶対最小限に表現し、
オンデマンドで必要なもの以外はすべて計算します。
たとえば、TODOリストを作成する場合は、TODOアイテムの配列を保持してください。
カウントのために別のstateの変数を保持しないでください。
代わりに、TODO数を表示する場合は、単にTODO項目配列のlengthを取ってください。
サンプルアプリケーションのデータ内の一つ一つを考えてみると、以下を持っていますね:
- 製品のリスト
- ユーザが入力した検索ワード
- チェックボックスの値
- フィルタされた製品のリスト
どれがstateかあててみよう。簡単な3つのチェックでわかります:
- それは親からpropsとして渡された? そうだとしたらstateではない
- 徐々に変化しない? そうだとしたらstateではない
- コンポーネントの中で他のstateや、propsに基づいて計算ができる? そうだとしたらstateではない
製品の元のリストはpropとして渡されるので、それはstateではありません。
検索テキストとチェックボックスは時間の経過とともに変化するため、また何かから計算することはできないため、stateと思われます。
最後に、フィルタリングされた製品リストは、元の製品リストと検索テキストとチェックボックスの値を組み合わせて計算できるため、stateではありません。
つまり、stateは以下のものです:
- ユーザが入力した検索ワード
- チェックボックスの値
See the Pen Thinking In React: Step 4 by Kevin Lacker (@lacker) on CodePen.
これで、アプリ状態の最小限の設定がわかりました。次に、どのコンポーネントがこの状態をかえるか、または所有するかを特定する必要があります。
覚えておくべきこと: Reactはすべて、コンポーネント階層を降りていく一方向のデータフローです。
どのコンポーネントがどの状態を所有すべきかはすぐには分かりません。 ここが、ビギナーがが理解するのに一番大変な部分っす
理解するためには以下の手順に従ってください:
アプリケーションの各stateについて:
- stateに基づいてなにかしらを表示するコンポーネントをすべて確認する
- 共通のオーナーコンポーネント(階層のなかでstateを必要とするすべてのコンポーネントの上にある)を探してください
- 共通のオーナーまたは上位階層の別のコンポーネントのいずれかがstateを所有する必要があります
- stateを所有すべきコンポーネントが見つからない場合は、単にstateを保持するための新しいコンポーネントを作成し、共通所有者コンポーネントの上の階層のどこかに追加します。
この戦略で実行してみる:
-
ProductTable
はstateに基づいて商品リストをフィルタリングする必要があり、SearchBar
は検索テキストとチェックstateを表示する必要があります。 - 共通のオーナーコンポーネントは
FilterableProductTable
です - 概念的には、フィルタテキストとチェックされた値が
FilterableProductTable
の中に生存します
いい感じです、stateはFilterableProductTable
の中にあると判断しました。
最初に、インスタンスプロパティ this.state = {filterText: ''、inStockOnly:false}
を
FilterableProductTable
の constructor
に追加して、アプリケーションの初期状態を反映させます。
次に、filterText
とinStockOnly
を ProductTable
と SearchBar
にpropとして渡します。
最後に、これらのpropを使用して ProductTable
の行をフィルタリングし、
SearchBar
のフォームフィールドの値を設定します。
アプリケーションの振る舞いを見ることができます: filterText
を"ball"
にてアプリをリフレッシュしてください。
データテーブルが正しく更新されていることがわかります。
See the Pen Thinking In React: Step 5 on CodePen.
これまでは、propの関数のとおり正しくレンダリングするアプリを作成し、stateは階層の下に流れました。
今度は、データを別の方法で流すことをサポートする時間です:
階層の深いフォームコンポーネントは、 FilterableProductTable
のstateを更新する必要があります。
Reactは、このデータフローを明示的にして、プログラムの仕組みを理解しやすくしますが、従来の双方向データバインディングよりも少しタイピングが必要です。
現在のバージョンの例で入力するか、チェックボックスをオンにすると、Reactが入力を無視することがわかります。
これは意図的なもので、 input
の value
propは FilterableProductTable
から渡された state
と常に等しくなるように設定しています。
何をしたいのか考えてみましょう。
ユーザーがフォームを変更するたびに、ユーザー入力を反映するようにstateを更新する必要があります。
コンポーネントは自分の状態だけを更新する必要があるので、 FilterableProductTable
は SearchBar
にコールバックを渡します。
このコールバックはstateを更新する必要があるときは常に起動します。
入力に対してonChange
イベントを使用して通知することができます。
FilterableProductTable
によって渡されたコールバックはsetState()
を呼び出し、アプリケーションは更新されます。
これは複雑に思えますが、ほんの数行のコードです。
そして、データがアプリ全体でどのように流れているかは実にに明白です。
願わくば、Reactを使ってコンポーネントやアプリケーションを構築する方法を考えるアイデアとなってほしいです。
以前よりも少し多くタイピングするかもしれませんが、実際に書かれたコードよりもはるかに多くが読み込まれていることを覚えておいてください。
このモジュラと明示的なコードを読むのは非常に簡単です。あなたがコンポーネントの大きなライブラリを構築し始めると、
この明確さとモジュール性に感謝し、コードの再利用によって、コード行が縮小し始めるでしょう:)