【技術書まとめ】『りあクト！ TypeScriptで始めるつらくないReact開発 第3.1版【Ⅲ. React応用編】』を読んだまとめ

- SPAはコンポーネントの初回レンダリング時にトップに強制スクロールさせる
- `React Router`バージョン6
    - v5からv6への変更点
        - `<Switch>`と`<Routes>` の違い
            - 最後まで評価してベストマッチした`<Route>`にルーティングされる
                - 並び順は問題とならない
                    - 新規追加や書き替えがやりやすい
                    - 可読性優先で並べられる
            - `nested routes`で一箇所に集約できる
                - ネストしたコンポーネントに対応したルーティングにしやすい
            - `<Routes>`の中では相対パスで記述できる
            - `History`オブジェクトの廃止
                - `navigate`関数に集約された
            - `<Redirect>`の廃止
                - `<Navigate>`を使うようになった
- `Redux`
    - 思想
        - Single source of truth（信頼できる唯一の情報源）
            - 状態は store オブジェクトのツリー構造のみ
        - State is read-only（状態は読み取り専用）
            - store の変更手段は action の発行のみ
                - ログをとって状態変化も再現できる
        - Changes are made with pure functions（変更は純粋関数にて行われる）
            - store
                - 状態格納の一つのステートツリー
                - 純粋関数の更新装置 reducer
                    - `(prevState, action) => newState`
                    - ステートマシン
                        - 入力条件と現在の状態で次の状態が決まるモデル
                    - 還元する
    - `action`
        - どんなイベントが起こったのかを表現するプレーンなオブジェクト
- `Redux`公式スタイルガイド
    - 優先度: A
        1. state を直接書き替えない
        2. reducer に副作用を持たせない
            - 外部システムと通信しない
            - reducer 外の変数を書き替えない
            - ランダムな値を store へ渡さない
        3. シリアライズできない値を state や action に入れない
            - Promise や関数やクラスインスタンスを state や action に入れない
                - `JSON.stringfy()`したとき値が同一と保証されない
        4. store はひとつのアプリにひとつだけ
    - Action に関するルール
        - action を state ではなくイベントとしてモデリングする
            - `setName`は`profileUpdated`となる
                - `set*`が減る
        - action の名前は意味を的確に表現したものにする
        - action タイプ名を「ドメインモデル/イベント種別」のフォーマットで書く
            - `user/profileUpdated`と書く
        - action を FSA に準拠させる
            - action は `type`,`payload?`,`error?`,`meta?`で構成される
                - 正常系は`type`と`payload`
                    - データは`payload`に入れる
        - dispatch する action は直に書かず action creator を使って作る
            - ❌`dispatch({ type: 'counter/incremented' })`
    - ツールやデザインパターンの利用に関するルール
        - Redux のロジックを書くときは Redux Tooklit を使う
        - イミュータブルな状態の更新には Immer を使う
            - `...article.comments`などをなくしてくれる
                - `draftAarticle.comments['23332'].body = 'Yaaah!';`
        - デバッグには Redux DevTools を使う
        - ファイル構造には「Feature Folder」または Ducks パターンを適用する
            - Feature Folder
                - `user/user-actions.ts`のようなもの
            - Ducks パターン
                - `src/ducks/user.ts`などでまとめる
    - その他設計に関するルール
        - どの状態をどこに持たせるかは柔軟に考える
        - フォームの状態を Redux に入れない
            - React Hook Form
        - 複雑なロジックはコンポーネントの外に追い出す
        - 非同期処理には Redux Thunk を使う
            - Hooksファーストの時代に Redux ミドルウェアが必要か疑問
- Redux Toolkit
    - `configureStore`
        - デフォルト値が設定可能
    - `createReducer`
        - reducer の作成を簡単にしてくれる
    - `createAction`
        - action creator を作成する
    - `createSlice`
        - action の定義と action creator, reducer をまとめて生成できる
            - 必然的に Ducks パターンとなる
                - `features/`に feature ごとに slice ファイルを置く
            - 複雑な型定義がいらない
            - 冗長な swith-case 文もいらない
            - reducer の戻り値が void で何も返さないと state 更新処理をしてくれる
            - 58行→20行になった
- `Hooks API`の`useReducer`
    - `const [state, dispatch] = useReducer(reducer, initialState);`
        - `useState`
    - Redux Toolkit の slice が使える
- 非同期通信
    - `Redux Thunk`
        - action creator を魔改造
    - `redux-saga`
        - 書き方にクセがあるが副作用処理をアプリから完全分離できる
- 非同期通信時の問題
    - ライフサイクルメソッド内での非同期通信はミドルウェアが解決した
        - 機能的凝集度が低い
        - ビジネスロジックの分離が難しい
        - テスタビリティが低い
        - コンポーネント間のデータ共有が難しい
    - 新たな問題
        - 学習コストが高い
        - コードのボイラープレートが多い
        - store の構造が過度に複雑化する
        - ベストプラクティスが定まらない
    - `Effect Hook`
        - 状態を`State Hook`で持つ
        - `Effect Hook`の中で副作用を実行
            - `useEffect`内で`async/await`を使う
        - 結果を`state`に格納する
- Suspense
    - `Effect Hook`の難しさ
        - 無限ループに陥りやすい
        - 宣言的でない
            - 命令型
                - 手順を時系列に沿って書き下していく
            - 宣言型
                - 「ここにはこのデータが入るべき。後はそっちでよしなにやってくれ」
    - `Suspense`を非同期通信に使う
        - 外部APIへ非同期通信する
        - そのPromise を throw する
        - Promise が解決したらそのデータを埋め込んだコンポーネントを返す
        - これを Suspense で待ち受ける
        - データ取得までは fallback を表示し、取得できたら中身が表示されるUIが作れる
    - メリット
        - パフォーマンス計測が改善する
            - FCP
            - FMP
            - LCP
- Concurrent モード
    - UXファースト
        - fetch-on-renderでのウォーターフォール問題の解決
        - race condition 問題が解決