Zustand State Architecture
Relevant source files
The following files were used as context for generating this wiki page:
The Zustand State Architecture in Dreamcats provides a centralized, reactive, and persistent management system for the application's global state. It is built using Zustand v5, utilizing a sliced architecture to separate concerns between user sessions, gameplay logic, UI state, and network status. The architecture is designed for high performance, employing shallow equality checks and auto-generated selectors to minimize unnecessary React re-renders.
This system serves as the primary bridge between the React frontend and the Convex backend, ensuring that local UI state remains synchronized with remote game data. Key features include built-in persistence for user preferences, a robust migration system for state schema updates, and a specialized tutorial store to manage onboarding flows.
Core Store Configuration
The main application state is managed by useAppStore, which aggregates multiple functional slices into a single state tree. The store utilizes several Zustand middlewares to enhance functionality, including devtools for debugging, persist for local storage synchronization, and subscribeWithSelector for fine-grained state subscriptions.
The store is configured with a versioned persistence layer (version 2) that includes a migration function to handle schema changes, such as transitioning legacy sound settings.
Sources: src/state/store.ts:47-106, src/state/types.ts:60-61
Store Slices
The architecture is divided into four primary interfaces that combine to form the AppState.
| Slice | Responsibility | Key Properties |
|---|---|---|
| SessionSlice | User identity and preferences | playerId, playerName, theme, locale, soundEnabled |
| GameSlice | Active game state and history | game, roomStatus, gameVersion, actionMessage |
| UISlice | Visual interface state | isMenuOpen, isSheetOpen, safeArea, viewportHeight |
| NetSlice | Connection and latency tracking | netStatus, latencyMs, reconnectAttempts |
Sources: src/state/types.ts:16-58, src/state/store.ts:55-58
State Access and Selectors
To optimize performance, the architecture implements two distinct patterns for accessing state: auto-generated selectors and shallow-hooked selectors.
Auto-Generated Selectors
The createSelectors helper utility transforms the standard Zustand store by adding a .use property. This allows developers to access state keys as individual hooks (e.g., useAppStore.use.playerId()), which automatically optimizes re-renders by subscribing only to that specific key.
Sources: src/state/store.ts:17-30, src/tests/store.test.ts:285-292
Shallow Selection Patterns
For components requiring multiple state fields, the project provides specialized hooks in src/state/selectors.ts that use useShallow. This ensures the component only re-renders if the selected properties actually change.
Persistence and Session Management
The state architecture includes a dedicated persistence layer to handle rejoins and session recovery. The useSessionPersistence hook manages the lifecycle of these sessions.
- Online Sessions: Automatically saves the
roomIdandplayerIdwhen a user joins an online game. - Hotseat Games: Periodically debounces the entire
gameobject to local storage (every 2000ms) to allow game recovery after accidental refreshes. - Selective Persistence: Only specific fields like player info, locale, and theme are persisted across sessions to avoid bloat.
Sources: src/hooks/useSessionPersistence.ts:15-68, src/state/store.ts:32-40
Specialized Stores
In addition to the main application store, the architecture includes specialized stores for isolated logic.
Tutorial Store
The useTutorialStore manages the onboarding flow through a linear state machine. It tracks the current TutorialStep and provides methods for navigation between steps.
Standalone Game Store
A simplified useGameStore exists in src/stores/gameStore.ts, primarily used for managing the immediate GameState object and the local player ID without the overhead of the full app store slices.
Sources: src/stores/gameStore.ts:25-46
Conclusion
The Zustand State Architecture in Dreamcats provides a modular and efficient framework for game state management. By combining sliced state definitions with aggressive memoization through selectors and deep persistence logic, it ensures a smooth user experience even during complex multiplayer interactions or network disruptions. The use of middleware for migrations and devtools further enhances the maintainability and debuggability of the system.