React公式ドキュメント 学ぶメモ

## はじめに
完全に自分用の備忘録です。 
Reactの学ぶを全て読む過程でメモ書きを見れば内容が頭に浮かぶように重要な部分を箇条書きで抜き出しました。

## 初めてのUI
```
三項演算子で可読性が落ちる場合は積極的に「if文」を用いてJSXとロジックを分離させる
 - stateによるclass名の出しわけも分離した方が綺麗
リストのレンダーはロジック部分でJSXの配列を作成すると綺麗に分離できる
JSXの重複や単純化はコンポーネント化してpropsを受け取り共通化

コンポーネントは純関数であることを前提としている(propsで参照型の値を扱う時はコピーしてから使う)
  - 1 同じ入力には同じ出力
  - 2 コンポーネント外部の変数を読み書きしない(呼び出される前に存在していたオブジェクトや変数を変更しない)
  - ※ コンポーネントの出力をレンダリング回数に依存させない
  - ※ 副作用はhandler内部でstateを使って表現する (local mutationはOK)
  - ※ useEffectによる副作用は最終手段
    
※ 外で定義されたfoods: obj[]を使ってレンダリングするのは順関数と言えるのか (下記2点を満たしているので言える)
  - 表示内容がレンダリング回数に依存しない(同じ引数の時に実行結果が同じになる)
  - 外部の値を変更していない (副作用を発生させない)
```
[ZEN記事](https://zenn.dev/kisukeyas/articles/887b90acdc88ce)
## インタラクティビティの追加
```
state: コンポーネント毎に独立した固有のメモリ
  - 1 コンポーネントの再レンダー間でデータを保持する
  - 2 stateの更新と新しいデータでコンポーネントを再レンダーするトリガー
  - ※ 通常はイベントハンドの中で更新される
  - ※ stateはスナップショットのようなもので、実際に値が変更されるのは次のレンダー時
  - ※ stateには関数コンポーネント(or カスタムフック)を呼び出した時点の値が代入されている「個々のレンダー内のstateは固定」
  - ※ 前回のstateに基づいて更新されるstateは更新関数を渡した方が安全 (チャレンジ問題参照)
  - ※ handlerは慣習としてhandleHogeと命名される。 それを受け取るpropsはonHogeと命名される

Reactのレンダリングの順番
 - 1 トリガー 「再レンダーをReactに要求」(初回やstate更新)
 - 2 レンダー 「再レンダーの対象を計算/確認し呼び出す (返却されるJSXはその時点でのスナップショット)」(更新されたstateの属するコンポーネントを特定し、子孫を対象にする)
 - 3 コミット 「前回のレンダーと再レンダーの差分がある箇所にコミット(DOMを変更)する」
 - ※ ペイント 「コミット終了後ブラウザが画面を再描画する」(これはReactのレンダリングの外の話)
 - ※ Reactの役割はMVCのCに似ている (客) (ウェイターReact) 厨房(Component Kitchen)
 - ※ コミット時は再レンダー対象のうち、前回のレンダーと違いがある箇所のDOMだけ変更する

イベントハンドラー
 - イベントハンドラーは唯一の引数eventを受け取る
 - イベントは子要素由来だとしても上の層へと伝播する "e.stopPropagation()"で伝播を防げる
 - domのデフォルト機能を停止させる場合は "e.preventDefault()"
```
[stateはスナップショットである](https://ja.react.dev/learn/state-as-a-snapshot#state-over-time)
[公式 Reactのレンダリングの仕組み](https://ja.react.dev/learn/render-and-commit)
[非同期処理の絡んだsetStateに更新関数を渡すチャレンジ問題](https://ja.react.dev/learn/queueing-a-series-of-state-updates#challenges)

## stateの管理

```
手続型(命令型): 命令する型が間違えると目的地に着かない
宣言型(関数型): 行き先は決まっている。命令はどこにいくかを選択するだけ
Reactの宣言型プログラミング: 視覚状態ごとに UI を記述すること
コンポーネントを開発するときの手順:
  - 1 コンポーネントの視覚状態をすべて特定
  - 2 状態を変更するための人間およびコンピュータのトリガを決定
  - 3 useStateで「state」をモデル化
  - 4 バグや矛盾を避けるため、不必要な state を削除 (快適なコンポーネント...を参照する)
  - 5 state を設定するためのイベントハンドラを接続

state構造の選択
  - 1 関連するstateをグループ化する (同時に更新するならまとめる)
  - 2 state の矛盾を避ける
  - 3 冗長な state を避ける (レンダリング時に計算可, propsをstateに入れない)
  - 4 state 内の重複を避ける (items, selectedItemはidを保存する) (複数のstate, ネストしたobj間で重複させない)
  - 5 深くネストされた state を避ける

stateのリフトアップ (単純なon/off) (searchbarとfilterdList)等
  - ※ 複数のコンポーネントを協調動作させたい
  - 1 共通の親にstateを移動する
  - 2 props経由で情報を下に渡す
  - 3 イベントハンドラを下に渡す

制御コンポーネント: propsによって駆動 (親が制御できる)
非制御コンポーネント stateによって駆動

----------------------------------------
stateの保持とリセット
- stateは「レンダーツリー(UIツリー)内のコンポーネントの位置」に紐づけてを管理される
- コンポーネントの位置(親含め)が同様でである限りstateは保持される
- UIツリーが変更されると、その下のツリーのstateも初期化される (親の位置が変わると子供のstateも初期化される) (sectionがdivに変更されるなど)
- ※ 同じ位置かの判断基準はJSXの位置ではなく、「レンダーツリー」で判断される (divの最初の子要素がComponentの場合 div > Componentのツリーが形成される)
- ※ 再レンダー間で state を維持したい場合、ツリーの構造はレンダー間で「合致」する必要がある
stateがリセットされるタイミング
  - 1 UIツリーの位置が変更されたとき
  - 2 親の位置が変更されたとき
  - 3 位置は同じでも再定義等によりコンポーネントが同じものじゃないとき
  - 4 keyで明示的にリセットするとき
  - ※ stateをリセットしたい場合、異なる位置でレンダーするか、keyを使う
-----------------------------------------

削除されたコンポーネントのstateの保持
  - 1 CSSで隠してDOMを消さない
  - 2 stateのリストアップで親で管理する
  - 3 localStorageから読み込んでstateを初期化するなど第２の情報源を利用

明示的にkeyを渡すタイミング
 - stateのリセットをしたいとき
 - DOMを再作成したいとき
 - 同じコンポーネント同士の位置を入れ替えるときにstateも入れ替えたいとき
 - ※ stateはUIツリーの位置と関連づけられているが、keyを使用して表示順に依存しない、名前付きの位置情報を指定できる (再レンダー間のstateの照合が可能)

コンポーネントをネストさせてはいけない
  - 親のstateが更新されるたびに子コンポーネントが「再定義」される
  - 再定義によりstateが初期化される

reducerの使い道
  - stateのロジックを集約し管理しやすいようにする
従来のstate更新からreducerへの移行手順
  1. イベントハンドラからアクションをディスパッチする。
  2. state とactionから次の state を返すリデューサ関数を書く。
  3. useStateをuseReducerに置き換える。

contextの使い道
  - propsのバケツリレーを解消できる
  - 1 コンテクストを作成する (createContextで作成)
  - 2 コンテクストを使用する (useContextで作成したContextを利用)
  - 3 コンテクストを提供する (Providerで提供する) 提供がない場合デフォルト値を利用
  - ※ 公式ドキュメントの学ぶを確認すると良い
contextを使い前に検討すること
  - 1 まずはpropsを渡す方法から始める
  - 2 コンポーネントを抽出して、childrenをJSX として渡す方法を検討
```
レンダリング位置の違い
```ts
// 下記は同じ位置にレンダー
<div>
  { flag ? <Component name="tee" /> : <Component key="baru" /> }
</div>

// 下記は異なる位置にレンダー
<div>
  { flag && <Component name="tee" /> }
  { flag || <Component key="baru" /> } 
</div>
```
[公式ドキュメント コンポーネント作成手順](https://ja.react.dev/learn/reacting-to-input-with-state#step-3-represent-the-state-in-memory-with-usestate)
[公式ドキュメント state構造の選択](https://ja.react.dev/learn/choosing-the-state-structure#avoid-redundant-state)
[4のitems: obj[]について学べる公式ドキュメント 特定のケースで不具合に繋がる](https://ja.react.dev/learn/choosing-the-state-structure#avoid-duplication-in-state)
[Context 学ぶ](https://ja.react.dev/learn/passing-data-deeply-with-context)

## 避難ハッチ

```
ref
  レンダーに使用されない値を保存するための非難ハッチ. (JSX表示や分岐条件で利用しない)
  外部API(多くの場合コンポーネントの外観に影響を与えないブラウザAPIと通信する必要がある場合に利用される)
  使用するタイミング
    - 1 レンダー間で情報を保持したいが、再レンダーが不要なとき (レンダーに使用される値はstateに保存すべき)
    - 2 DOM要素にアクセスしたいとき (通常はこちらの用途が多い) (フォーカス、スクロール等非破壊的なアクションに使用)
  refのベストプラクティス
    - refを避難ハッチとして扱う
    - レンダー中にrfc.currentを読み書きしない (if (!ref) ref = 1 のような初回に1度だけ実行するコードは例外)
  - ※ 外部コンポーネントのDOMにアクセスしたい場合forwardRefを使う 
  - ※ refにアクセスするのは通常イベントハンドラから。それをする特定のイベントがない場合useEffectを利用する
  - ※ スクロール等でstateを同期的に処理する必要がある場合flushSyncを使用する (stateを同期実行させる方法)
  - ※ レンダリング中にrefを通じて「何か」をしようとしてはいけない
  - ※ reactがref.currentをアタッチするのはコミット中

useEffect
  - レンダー自体によって引き起こされる副作用を指定するためのもの (イベント起因ではない)
  - コンポーネントがレンダリングされた後実行される
  - 何らかの外部システムと同期するために使用される (WebAPI, third-party制のコード, 外部API等)
useEffectを実装する手順
  - 1 エフェクトを宣言する
  - 2 依存値の配列を指定
  - 3 必要に応じてクリーンアップ (接続には切断, 登録には解除, 取得にはキャンセル or 無視が必要) (APIによっては連続で呼び出すとエラーになるものもある)
useEffectのポイント
  - レンダー中に計算できるものは計算する
  - fetch処理の競合状態に気をつける(クリーンアップする)
  - どのように同期を開始し、どのように同期を終了するのかに注目する(更新中なのか、アンマウント中なのかは問題じゃない)
  - 1つのエフェクトは、1つの独立した同期の処理を表すべき
  - 常にカスタムフックにラップすることでよりわかりやすくならないか検討する
  - useEffectEventでリアクティブなものとそうでないものを分岐できる
  - setIntervalやLisnnerやfetchはクリーンアップをする必要がある
  - エフェクトが再マウントにより壊れる場合、クリーンアップ関数を実装する必要がある
  - アプリケーションの初期化はuseEffectではない (コンポーネントの外に置く)
```


```
カスタムフック
  - コンポーネント間でロジックを共有できる (state自体ではなくロジック)
  - 名前はuseで初めて大文字で続ける必要がある
  - useEffectがよく内包される (useeffectを書くときは常にカスタムフック化で処理がより明確にならないかを考える)
  - カスタムフックのコードは、コンポーネントの本体の一部だと考える (再レンダーと共に再度呼び出される) (propsやstateは常に最新のものを読み込む)
  - カスタムフックが受け取るイベントハンドラはエフェクトイベントにラップする (useEffect内で利用するとき?)
  - カスタムフックは具体的かつ高レベルなユースケースに対して使う
    - 「useMount」のようなカスタムフックを作成してはいけない (抽象的すぎる)
    - 理想的には、カスタムフックの名前は、コードをあまり書かない人でも、何をするのか、何を受け取るのか、何を返すのかを推測できるほどに明確であるべき
カスタムフック化の利点
  1. エフェクトに出入りするデータの流れが非常に明確になる。(useEffectを内包する場合)
  2. コンポーネントがエフェクトの実装そのものではなく、意図にフォーカスできるようになる。
  3. React が新しい機能を追加したときに、コンポーネントを変更せずにエフェクトを削除できるようになる。 (将来的に組み込みにfetch機能が実装される可能性がある)
※ 良いカスタムフックとは、動作を制約することで呼び出し側のコードをより宣言的にするもの (そうでない場合長期的にはメリット < デメリットになる可能性が高い)
```

## おわりに
Reactを何となくで触っている状態から裏側で何が起きているのか理解することがでるようになります。
より実践的なのはstateの管理でしょうか