Skip to content

Migrate state management from MobX to Zustand with Immer#4

Merged
stefanwille merged 4 commits intomasterfrom
claude/migrate-to-zustand-Dloro
Jan 25, 2026
Merged

Migrate state management from MobX to Zustand with Immer#4
stefanwille merged 4 commits intomasterfrom
claude/migrate-to-zustand-Dloro

Conversation

@stefanwille
Copy link
Copy Markdown
Owner

Summary

This PR replaces the MobX-based state management system with Zustand and Immer middleware, simplifying the codebase while maintaining all existing functionality. The new store uses a single source of truth with explicit state mutations through Immer's draft-based API.

Key Changes

  • State Management: Migrated from MobX Store and Game classes to a Zustand store (useGameStore) with Immer middleware for immutable updates

  • Store Structure: Created new src/model/store/ directory with:

    • gameStore.ts - Main Zustand store with state and actions
    • types.ts - TypeScript type definitions for all state shapes
    • initialState.ts - Factory functions for creating initial state
    • ghostHelpers.ts - Helper functions for ghost computed values
    • constants.ts - Game constants (timers, speeds, scoring)
  • State Machines: Implemented PacMan and Ghost state transitions directly in the store using pure functions (pacManTransition, ghostTransition) instead of XState

    • sendPacManEvent() and sendGhostEvent() handle state transitions
    • Events: ENERGIZER_EATEN, COLLISION_WITH_GHOST, PHASE_END, REVIVED, etc.
  • Component Integration:

    • Removed StoreContext provider pattern; store is now globally accessible
    • Updated StoreContext.ts to provide compatibility hooks (useStore, useGame, useDebugState) that delegate to Zustand selectors
    • Simplified App.tsx by removing provider wrapper
  • Game Loop: Updated onAnimationFrame.ts to work with Zustand state mutations instead of MobX actions

  • Tests: Updated detectCollisions.test.ts to use Zustand store directly with useGameStore.setState() and useGameStore.getState()

  • Dependencies: Added zustand@^5.0.10 and immer@^11.1.3; kept MobX/XState for backward compatibility with legacy test files

Implementation Details

  • State mutations use Immer's draft-based API for safe immutable updates
  • Selectors are provided for computed values (e.g., selectPacManDead, selectEnergizerTimeLeft)
  • Ghost and PacMan state machines use explicit transition tables for clarity
  • All game actions are now methods on the store, eliminating the need for separate class instances
  • Backward compatibility maintained through re-exported hooks in StoreContext.ts

Migration Notes

Some test files still import from legacy MobX-based classes (Store.ts, Game.ts, PacMan.ts, Ghost.ts) for isolated unit testing. The main application uses Zustand exclusively.

Replace MobX observable classes and XState state machines with a
centralized Zustand store using Immer middleware for immutable updates.

Key changes:
- Create new src/model/store/ directory with Zustand store structure
  - gameStore.ts: main store with state and actions
  - types.ts: TypeScript interfaces for all state
  - initialState.ts: factory functions for initial state
  - ghostHelpers.ts: computed property helpers for ghosts
  - constants.ts: game timing constants
- Implement state machine transitions directly in Zustand actions
  - sendPacManEvent: eating → chasing → dead
  - sendGhostEvent: scatter ↔ chase ↔ frightened → dead
- Update all game logic to use useGameStore.getState() pattern
- Remove observer HOC from all React components
- Convert components to use useGameStore hooks with selectors
- Update test files to use new store reset pattern
- Convert WayFindingPage from MobX local store to React useState

The main application now exclusively uses Zustand. Legacy MobX classes
are retained for isolated unit tests of the original class behavior.
@vercel
Copy link
Copy Markdown

vercel bot commented Jan 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
pacman-react Ready Ready Preview, Comment Jan 25, 2026 7:16pm

Request Review

Updated all relevant test files and model components to import from LegacyStore instead of the removed Store class. This change ensures compatibility with the new Zustand state management system while retaining legacy functionality for unit tests.
@stefanwille stefanwille merged commit 5515062 into master Jan 25, 2026
2 of 3 checks passed
@stefanwille stefanwille deleted the claude/migrate-to-zustand-Dloro branch January 25, 2026 19:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants