📄
概念 📚 software-design-concepts

状態管理

ローカル状態・グローバル状態・サーバー状態の分類と、適切な状態管理ライブラリの選択基準

フロントエンドの状態管理が複雑になる根本的な原因の一つは、「どこで何を管理するか」の境界が曖昧になることにある。状態を適切に分類すると、UI状態(ドロップダウンの開閉・フォームの入力値等)・アプリケーション状態(ログインユーザーの情報等)・サーバー状態(APIから取得したデータ)・URL状態(検索条件やページ番号)の4種類に整理できる。これらを同一の状態管理ライブラリで一元管理しようとすることが、不必要な複雑さを生む原因になる。

サーバー状態はキャッシュ・再フェッチ・バックグラウンド更新・ローディング/エラー状態の管理という独自のライフサイクルを持つ。React QueryやSWRはこのサーバー状態管理に特化したライブラリであり、APIデータのキャッシュ・stale-while-revalidate戦略・楽観的更新(Optimistic Update)を宣言的に扱える。従来のReduxでAPIデータを管理していたコードの多くは、React Queryに移行することで大幅にシンプル化できる。

ZustandやJotai・Recoilはグローバルなクライアント状態管理に適したライブラリである。ReduxのFluxパターンは予測可能な状態遷移という価値を持つが、アクション・リデューサー・セレクターのボイラープレートが多い。Zustandはこのボイラープレートを大幅に削減しながら同様の予測可能性を提供する。Jotaiはアトム(Atom)単位で状態を定義し、必要なコンポーネントのみが再レンダリングされるきめ細かな最適化が可能である。

コードレビューで着目するポイント

  • サーバー状態がRedux等のクライアント状態管理ストアに格納されていないか(React QueryやSWRに移行すべき)
  • グローバル状態が本当にグローバルに必要なものか(コンポーネントのローカル状態で足りないか)
  • Context APIのProviderが不必要に高い位置に置かれており、関係のないコンポーネントの再レンダリングを引き起こしていないか
  • 状態の正規化が行われているか(同じAPIデータが複数箇所に重複して保持されていないか)
  • URL状態(フィルター・ページネーション・タブ)がURL(クエリパラメータ等)で管理されているか(ブラウザバックで状態が復元できるか)
  • 楽観的更新(Optimistic Update)を使用している場合、エラー時のロールバック処理が実装されているか

典型的なアンチパターン

サーバー状態をReduxで管理: APIから取得したデータをReduxストアに格納し、ローディング状態・エラー状態・キャッシュ無効化を手動で管理するコードは非常に冗長になる。React Queryが提供するキャッシュ戦略・再フェッチロジックをゼロから再実装することになり、バグも生まれやすい。

Context APIによる頻繁な更新: 高頻度で更新される状態(入力値・アニメーション等)をContextに入れると、Providerの子孫全コンポーネントが毎回再レンダリングされパフォーマンスが劣化する。頻繁に更新される状態はコンポーネントのローカル状態またはZustand等の選択的サブスクリプションができるライブラリで管理すべきである。

フィルター・ページ番号のステート管理: 検索条件やページ番号をuseStateで管理すると、URLを共有してもその状態が再現されず、ブラウザバックでも状態が失われる。このような状態はURLのクエリパラメータで管理することで、共有可能性と履歴管理を無料で得られる。

参考リソース

  • ツール: TanStack Query(React Query) - サーバー状態管理のデファクトスタンダード
  • ツール: Zustand - シンプルなAPIのグローバル状態管理ライブラリ
  • ツール: Jotai - アトムベースの細粒度状態管理ライブラリ
  • 記事: Application State Management with React - Kent C. Doddsによる状態の分類と管理戦略の解説
  • ツール: Redux Toolkit - Reduxのボイラープレートを削減した公式ツールキット(Reduxが必要な場合の現代的なアプローチ)
  1. 1. 📄アーキテクチャスタイル
  2. 2. 📄ドメインモデリング
  3. 3. 📄モジュール分割と依存管理
  4. 4. 📄データモデリング
  5. 5. 📄API設計
  6. 6. 📄整合性とトランザクション
  7. 7. 📄非同期処理(Queue/Event)
  8. 8. 📄キャッシング
  9. 9. 📄ユーザーリサーチ
  10. 10. 📄情報アーキテクチャ
  11. 11. 📄インタラクションデザイン
  12. 12. 📄UX原則とヒューリスティクス
  13. 13. 📄アクセシビリティ(UX観点)
  14. 14. 📄UXメトリクス
  15. 15. 📄スケーラビリティ
  16. 16. 📄可用性とレジリエンス
  17. 17. 📄オブザーバビリティ
  18. 18. 📄環境・インフラ設計
  19. 19. 📄データマイグレーション
  20. 20. 📄セキュリティ設計原則
  21. 21. 📄データ保護とマルチテナント
  22. 22. 📄LLMセキュリティ
  23. 23. 📄ビジュアルデザイン原則
  24. 24. 📄デザインシステム
  25. 25. 📄コンポーネント設計
  26. 26. 📄スタイリング
  27. 27. 📄状態管理
  28. 28. 📄フロントエンドパフォーマンス
  29. 29. 📄アクセシビリティ(実装観点)
  30. 30. 📄アニメーションとインタラクション
  31. 31. 📄設計原則
  32. 32. 📄デザインパターン(GoF)
  33. 33. 📄エンタープライズパターン
  34. 34. 📄クリーンコード
  35. 35. 📄リファクタリング
  36. 36. 📄型設計とコントラクト
  37. 37. 📄関数型プログラミング概念
  38. 38. 📄エラーハンドリング
  39. 39. 📄テスト戦略と哲学
  40. 40. 📄テスト種別(機能テスト)
  41. 41. 📄テスト種別(UI・ビジュアル)
  42. 42. 📄テスト種別(契約・境界)
  43. 43. 📄テスト種別(非機能テスト)
  44. 44. 📄テストダブル
  45. 45. 📄テスト設計技法
  46. 46. 📄並行処理・マルチスレッド
  47. 47. 📄パフォーマンス最適化
  48. 48. 📄ドキュメント管理
  49. 49. 📄バージョン管理と開発プロセス
  50. 50. 📄脅威モデリング
  51. 51. 📄通信保護(TLS)
  52. 52. 📄暗号化・機密情報管理
  53. 53. 📄認証・セッション管理
  54. 54. 📄認可・アクセス制御
  55. 55. 📄入力バリデーション
  56. 56. 📄インジェクション攻撃
  57. 57. 📄出力エンコーディング
  58. 58. 📄エラーハンドリング(セキュリティ観点)
  59. 59. 📄SSRF(サーバーサイドリクエストフォージェリ)
  60. 60. 📄依存関係管理
  61. 61. 📄設計・実装 参考書籍
  62. 62. 📄セキュリティ参考資料
  63. 63. 📄正規化(データベース正規化)