Skip to content

状態管理アーキテクチャ

React Context API + useReducerを採用

日付: 2025-01-06

ステータス

~~2025-01-06 承認済み~~
2025-08-09 非推奨007-依存性注入とアーキテクチャリファクタリング.md で置換

コンテキスト

ぷよぷよゲームでは以下の状態管理が必要:

  • ゲーム状態(プレイ中、ポーズ、ゲームオーバー)
  • フィールドの状態(ぷよの配置)
  • スコア、連鎖数、レベル
  • 現在の操作中ぷよペア
  • NEXTキュー

候補として以下を検討:

  1. React Context API + useReducer
  2. Redux Toolkit
  3. Zustand
  4. Jotai
  5. ローカル状態のみ(useState)

決定

React Context API + useReducer を採用する

理由

Context API:

  • Reactの標準機能で追加の依存関係不要
  • 小〜中規模アプリケーションに適している
  • TypeScriptとの統合が容易
  • パフォーマンス問題は適切な設計で回避可能

useReducer:

  • Reduxライクな予測可能な状態更新
  • 複雑な状態変更ロジックを整理
  • 時間旅行デバッグに対応
  • アクションベースの設計でテストが容易

他の選択肢を除外した理由:

  • Redux: 小規模アプリには過剰な複雑さ
  • Zustand/Jotai: 学習コストと将来の保守性への懸念
  • ローカル状態のみ: コンポーネント間の状態共有が困難

影響

ポジティブな影響

  • シンプルさ: 外部依存なしで状態管理
  • 型安全性: TypeScriptとの完全な統合
  • テスタビリティ: Reducerの単体テストが容易
  • デバッグ性: React DevToolsでの状態追跡

ネガティブな影響

  • パフォーマンス: 不適切な設計時の不要な再レンダリング
  • ボイラープレート: アクション・リデューサーの定義が必要
  • スケーラビリティ: 大規模になった場合の複雑さ

軽減策

  • Context の適切な分割(ゲーム状態、UI状態)
  • useMemoとuseCallbackによる最適化
  • カスタムフックによるロジックの抽象化

アーキテクチャ詳細

Context 構成

// ゲーム状態用Context
const GameContext = createContext<GameState>();

// UI状態用Context  
const UIContext = createContext<UIState>();

Reducer パターン

type GameAction = 
  | { type: 'START_GAME' }
  | { type: 'MOVE_PUYO'; direction: Direction }
  | { type: 'ROTATE_PUYO' }
  | { type: 'DROP_PUYO' };

function gameReducer(state: GameState, action: GameAction): GameState {
  switch (action.type) {
    case 'START_GAME':
      return initializeGame();
    // ...
  }
}

カスタムフック

export function useGame() {
  const context = useContext(GameContext);
  if (!context) {
    throw new Error('useGame must be used within GameProvider');
  }
  return context;
}

コンプライアンス

この決定の遵守は以下により確認:

  • Context Provider の適切な配置
  • useReducer の使用
  • カスタムフックによる状態アクセス
  • TypeScript による型定義の存在

備考

  • 決定者: 開発チーム
  • 影響範囲: 状態管理全体
  • レビュー予定: プロトタイプ完成後またはパフォーマンス問題発生時