# React グローバルステート管理改善計画 ## 1. 背景と目的 現在のプロジェクトでは、グローバルな状態管理に SWR が中心的に利用されています。特に `useSWRStatic` や `useContextSWR` といったカスタムフックを用いて、クライアントサイドの状態管理も行われています。 しかし、以下の課題が認識されています。 * **パフォーマンスへの懸念:** アプリケーションの特定の箇所でパフォーマンスの問題が発生している可能性があります。SWR の再検証戦略やカスタムフックの実装が影響している可能性が考えられます。 * **潜在的なバグ:** 特に `useSWRStatic` 周りで、意図しない挙動やデータの不整合が発生している可能性が指摘されています。カスタムフックの複雑さやキャッシュの扱い方が原因である可能性があります。 これらの課題を解決し、より堅牢でメンテナンスしやすく、パフォーマンスの良い状態管理を実現することを目的とします。 ## 2. 基本方針: 役割分担の見直し SWR と、クライアントサイド状態管理に特化した軽量ライブラリ(Jotai)を併用する方針を採用します。 * **SWR:** データフェッチング、サーバーキャッシュ管理、非同期状態管理に特化して利用を継続します。リモートから取得するデータ(ページ情報、ユーザー情報など)の管理に適しています。 * **Jotai:** クライアントサイドで完結するUI状態や、同期的な状態管理を担当します。(例: モーダルの開閉、テーマ設定、フォーム入力値など) ```mermaid graph TD subgraph "提案: 役割分担" A[React Component] --> B{useSWR}; B --> C[SWR Cache (サーバーキャッシュ)]; C -- データフェッチ --> D[API Server]; A --> E{useAtom (Jotai)}; E --> F[Jotai Atoms (クライアント状態)]; end ``` この方針により、以下のメリットが期待されます。 * **責務の分離:** 各ライブラリの得意分野を活かし、コードの見通しが良くなります。 * **コードの簡潔化:** 複雑なカスタムフック (`useSWRStatic`, `useContextSWR`) が不要になる可能性があります。 * **パフォーマンス改善:** 不要な再レンダリングを抑制しやすくなります。 * **予測可能性の向上:** 状態の更新フローが明確になります。 ## 3. 具体的な計画ステップ 以下のステップで段階的に改善を進めます。 ### ステップ1: Jotai 導入 PoC (Proof of Concept) の実施 クライアントサイド状態管理ライブラリとして Jotai を導入し、その使用感やプロジェクトへの適合性を確認するため、小規模な PoC を実施します。 * **対象:** `useSWRStatic` や `useContextSWR` で管理されているクライアント状態の中から、比較的シンプルで影響範囲の小さいものをいくつか選定します。(例: `isDrawerOpened`, `sidebarContents`, `preferCollapsedMode` など) * **実施内容:** 選定した状態を Jotai で実装します。 * **確認観点:** * 実装の容易さ、コードの可読性 * TypeScript との親和性 * パフォーマンス(React DevTools で再レンダリングを確認) * テストのしやすさ * バンドルサイズへの影響 ### ステップ2: 段階的な移行 PoC の結果を踏まえ、Jotai を本格的に導入し、既存の状態管理を段階的に移行します。 1. **Jotai 導入:** Jotai をプロジェクトの依存関係に追加し、基本的な設定を行います。(PoC で実施済みであれば確認のみ) 2. **小規模な状態から移行:** まずは PoC で試した状態や、新規に追加されるクライアント状態から新しいライブラリでの管理を開始します。 3. **既存コードの置き換え:** `useSWRStatic` / `useContextSWR` を利用している箇所を特定し、クライアント状態管理の部分を新しいライブラリに置き換えていきます。 * SWR はデータフェッチングが必要な箇所では引き続き利用します。 * カスタムフック (`useSWRStatic`, `useContextSWR`) の利用箇所を徐々に減らしていきます。 4. **テストの更新:** 状態管理の変更に伴い、関連するユニットテストや E2E テストを更新し、デグレードが発生しないことを確認します。 ## 4. 期待される効果 * 状態管理コードの責務が明確になり、可読性とメンテナンス性が向上する。 * パフォーマンスが改善され、ユーザー体験が向上する。 * `useSWRStatic` などに起因する可能性のあったバグが解消される。 * モダンな状態管理ライブラリの知見がチームに蓄積される。 ## 5. 移行の進捗状況 ### 5.1 完了した移行 以下の状態を Jotai に移行完了しました: 1. **PoC フェーズ:** * `useDrawerOpened`: サイドバーのドロワー表示状態 * `usePreferCollapsedMode`: サイドバーの折りたたみモード設定(永続化含む) 2. **追加移行完了:** * `useSidebarMode`: サイドバーの表示モード管理(`DRAWER`, `COLLAPSED`, `DOCK`) * `editorMode` と `isDeviceLargerThanXl` の状態との連携 * 関連コンポーネントの更新(`PagePathNavSticky`, `Sidebar`, `SidebarContents`, `PrimaryItems`) ### 5.2 移行パターンの確立 移行を通じて、以下のパターンが確立されました: * **ディレクトリ構造:** Jotai の実装は `states/` ディレクトリに配置 * **依存関係の管理:** 複数の状態を組み合わせる場合(例: `useSidebarMode`)の実装パターン * **永続化の方法:** ユーザー設定の永続化が必要な状態の実装パターン ## 6. 今後の方針 ### 5.1 実施した PoC の概要 以下の2つの状態を Jotai を使用して実装し、検証を行いました: 1. **`useDrawerOpened`:** サイドバーのドロワー表示状態 2. **`usePreferCollapsedMode`:** サイドバーの折りたたみモード設定(ユーザー設定の永続化を含む) ### 5.2 実装内容 * 新しい `states/ui.ts` モジュールを作成し、Jotai の atoms とカスタムフックを実装 * 既存の SWR ベースの実装を削除 * 関連するコンポーネントを新しいカスタムフックを使用するように修正: * `DrawerToggler` * `GrowiNavbarBottom` * `EditorNavbarBottom` * `Sidebar` * `ToggleCollapseButton` * `useSidebarMode` * `pages/utils/commons.ts` の初期化処理を更新 ### 5.3 PoC の成果 * **コードの簡潔化:** SWR の仕組みを使った複雑なカスタムフックが、シンプルな Jotai の atoms とフックに置き換わりました。 * **責務の分離:** データフェッチングとクライアント状態管理の役割が明確に分かれました。 * **実装の直感性:** Jotai の API は React の `useState` に近く、理解しやすい実装となりました。 * **TypeScript との親和性:** Jotai は優れた型推論をサポートしており、型安全な実装が実現できました。 ### 5.4 今後の方針 PoC の結果を踏まえ、以下の方針で Jotai への移行を進めることを推奨します: 1. **段階的な移行:** * まず `useSWRStatic` で管理されている他の UI 状態(`useCurrentSidebarContents` など)を移行 * 次に `useContextSWR` による状態管理を見直し、適切なものを Jotai に移行 2. **パターン確立:** * PoC で確立したパターン(`states/` ディレクトリへの実装、命名規則など)を踏襲 * 永続化が必要な状態については `usePreferCollapsedMode` の実装パターンを参考に 3. **テスト戦略:** * Jotai の状態に対するユニットテストの方針を確立 * E2E テストでの状態管理変更の影響確認方法を整備 4. **ドキュメント整備:** * Jotai での状態管理パターンをチーム内で共有 * 新規開発時の状態管理の判断基準(SWR vs Jotai)を明確化 この方針で進めることで、段階的かつ安全に状態管理の改善を実現できると考えられます。