state の管理
このページでは、メンテナンスしやすい state の作り方や、props 以外で state を渡す方法について学びましょう。
状態(state)とは?
「ある物事のある時の様子」のことです。状態 A と状態 B が存在するとき、状態 A から状態 B になったりします。これを状態遷移と言います。
状態遷移図にすると次のようになります:
今度は、状態 B から状態 A にもなるようにしてみましょう。
さらに状態 C を追加して状態 A との間でだけ遷移するようにしてみましょう。
状態 G まで状態を増やしてみました…
どんどん状態遷移図が複雑になっていきます。これは、React でも同じことが言えます。状態は、可能な限り少なくしたほうがメンテナンスしやすく、バグが少ないコードになります。
それでは、state の管理の内容を進めていきましょう。
理解度チェック
学んだことを思い出しながら、折りたたみを展開して書かれているキーポイントが自分の理解と合っているか確認しましょう。
入力で変化する React コンポーネントの作り方
次のようにして入力に変化する実装をおこないます:
- 変化しうる「状態」を列挙する
- 状態が変化するトリガーを選ぶ
- 「状態」を
useStateで実装する - 不要な「状態」は削除する
- トリガーに対応するイベントハンドラーを実装する
state を使って入力に反応するで学びましょう。
state の構造の原則
次のような原則で state を作れば、メンテナンスしやすく、バグの少ない state になります。
- 関連する state は 1 つにまとめる
- 「どちらが正しいか分からない」(矛盾する)state は作らない
- 他の state から JavaScript 式で計算できる値は state にしない
- 同じ値の state は同じタイミングで更新する保証ができないので作らない
- 深くネストされた state は更新しにくいので作らない
state 構造の選択で学びましょう。
2 つのコンポーネントで同時に state を更新する方法
次のように state のリフトアップ (lifting state up) をおこなうことで実現できます:
- 2 つのコンポーネントから state を削除する
- 2 つのコンポーネントを呼び出している祖先コンポーネントに state を移動する
- props で 2 つのコンポーネントへ state を渡す
コンポーネント間で state を共有するで学びましょう。
state が保持またはリセットされる条件
保持される条件:
- コンポーネントを UI ツリー内の同じ位置でレンダーする
リセットされる条件:
- コンポーネントを UI ツリー内の異なる位置でレンダーする
- コンポーネントをレンダーから破棄する
- UI ツリー内の同じ位置で別のコンポーネントをレンダーする
state の保持とリセットで学びましょう。
複雑な state の更新を扱う方法
リデューサーを使用することで、複雑な更新処理をコンポーネントの外の関数で定義することができます。
state ロジックをリデューサに抽出するで学びましょう。
複雑な処理をコンポーネントの外の関数に定義する方法として、カスタムフックを作成する方法もあります。どちらかというとカスタムフックを作成することをおすすめします。
state を子孫コンポーネント同士に共有する方法
props を使うこともできますが、コンテキストを使えば中間のコンポーネントへの state の受け渡しを書かずに実現できます。
コンテクストで深くデータを受け渡すで学びましょう。
props でも children props を併用して、中間のコンポーネントへの受け渡しを不要にできます。また、コンテキストは値がどこから渡されているかが props より不明瞭なので、ほとんどのケースで props を使用することをおすすめします。
ただし、React の便利な外部ライブラリーではコンテキストを使用して値を渡すことが多いので、目に触れる機会は少なくありません。