【個人メモ】React v18学び直し

学習内容
React.js v18
- なんとなくで使ってきてしまったのであらためて基本の確認
- 方法:https://ja.react.dev/learn
⚠️注意⚠️
個人の学習記録(特に気になったことをメモする)目的のため、学習内容について体系的に記載するわけではありません

① React公式の立場としては、Reactを使うときはフレームワークの使用を推奨している
- 理由は、ルーティングやデータ取得などの問題に対処するためにフレームワークを使用した方が効率が良いから(+自前で対処すると独自フレームワークにようになってしまい、メンテンナンスが大変になるから)
- (おそらく)一部分だけReactを使用する場合はこの限りではない
② コンポーネントにpropsとしてわたす子要素の型は、React.ReactNodeとReact.ReactElementがある
- ReactNodeはJSXとプリミティブ型(文字列、数値)も受け入れる型
- ReactElementはJSXのみ受け入れる型
【todo】
- useMemoとuseCallbaakの違いが明確に理解できていない

③ コンポーネントにeventをトリガーとした関数を渡す場合の一般的な命名
- eventをsomethingとすると、
- props名 = onSomething
- 関数名 = handleSomething
④ 値の変更はイミュータブルにせよ
- オブジェクト・配列のような値を変更するときは、元の値をいじるのではなく、元の値から新しいオブジェクトをコピーしてその値を変更してね
- 理由:
- redo機能の実装に便利
- レンダリング最適化する際に値の比較が容易になる

⑤stateはDRYの原則を考慮して切り出す
- stateは最小限の単位にする。ある値とその値から派生する値が必要な場合は、派生する値は必要になった時に算出する(例:ショッピングリストと、そのリストに含まれるデータ数)
⑥コンポーネントの定義の内部に別のコンポーネントの定義しない
- 速度の低下とバグの原因になる
⑦Reactはコンポーネントが純粋関数であると想定している
- 純粋関数(入力が同じなら出力も常に同じ)であるようにする
- コンポーネントのレンダリング中に、コンポーネント外の既存の変数やオブジェクトを変更してはいけない
⑧Reactで何らかの変化を起こす場合、なるべくイベントハンドラを使用すること。 useEffect
は最終手段。
ただの感想
- StrictModeでの開発環境ではコンポーネント関数を2回呼び出している件(純粋関数であるかを検証するため)
デバッグ中にconsole.log
していて、2回出力されているなと気づいてはいたけどそういう仕様だったとは。てっきり書き方が悪くて無駄なレンダリングが発生しているのだと思っていた。

⑨コンポーネントがレンダーされる時、そのコンポーネントに紐づくprops、イベントハンドラ、ローカル変数はレンダー時のstateを元に算出される。
<button onClick={() => {
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);
}}>+3</button>
あるコンポーネントにこのようなUIが存在していて、コンポーネントレンダー時のstate "number"が0だった場合、number=0なので、全てのsetNumberは setNumber(0 + 1);
となる。
よって、setNumberによって引き起こされる次のレンダリング時のstate "number"の値は1。
⑩イベントハンドラ内のコードが実行されてからstateは更新される
(11)イベントの伝播(bubbleあるいはpropagate)
- Reactでは、
onScroll
以外のイベントは子コンポーネントから親コンポーネントに伝播する - 伝播させたくないときは、子コンポーネントのイベントハンドラに
e.stopPropagation()
を記述する
(12)”レンダー”とは、Reactがコンポーネントを呼び出し、何を画面に表示するべきなのか知ること。(Reactの文脈では、ブラウザが行うレンダリングは”ペイント”と呼称する)

(13)コンポーネント開発の仕方(以下、コピペ)
- コンポーネントの視覚状態をすべて特定する。
- 状態を変更するための人間およびコンピュータのトリガを決定する。
- useState で state をモデル化する。
- バグや矛盾を避けるため、不必要な state を削除する。
- state を設定するためのイベントハンドラを接続する。
(14)stateは更新時に間違いや漏れが発生しないように設定する

(15) useRef
- レンダー中に
ref.current
にアクセスすべきではない
(16) useEffect - レンダー後に実行される
- 外部システムとの連携のために使うこと(stateの変更など、React内部で完結するような処理は不適である)
- DOMの削除時に終了させる必要のある処理ペアをuseEffect内で開始したときは、クリーンアップ 関数で終了させる
- ”特定の処理をキャッシュしたい”という目的であれば、
useMemo
を使用すること
- 特定の処理がキャッシュするほど計算コストが高いかどうか:処理時間が1ms以上ならかなりの量といえる
-
console.time
とconsole.timeEnd
を使用して処理時間が調査できる
- useEffectの依存対象は”reactive”な値(レンダー間で変化する可能性がある値)。
- レンダー中に作成されたオブジェクトや関数は依存配列には含めないこと(レンダー毎に異なる値として判断されるため)。
ただの感想 ドキュメント曰く、「リンタが検出するエラーは全て妥当なのでリンタをオフにせず、コードを修正せよ」とのこと。ただ、オフにしてしまいがちなので、useEffectEventを検討中なのではないかな。

(16)カスタムフック
- ロジックを異なるコンポーネント間で再利用したい時に使う ※”再利用”であって”共有”ではない
- カスタムフック内のコードは再レンダーごとに実行される
- useEffectを使用する場合はカスタムフックを使う余地がないか検討する(使うことでわかりやすくなるか?)