State Management Skill
Zustand-based state management standards and best practices.
When to Apply
- •Creating new state stores
- •Sharing state between components
- •State architecture decisions
- •Performance optimization for state
State Category Guidelines
| Category | Solution | Use When |
|---|---|---|
| Local UI | useState | Single component, simple state |
| Shared UI | Zustand store | Multiple components need same data |
| Server data | React Query / SWR | API data with caching needs |
| Form state | useState / form library | Form inputs, validation |
| URL state | useSearchParams | Filter/sort params, shareable URLs |
Zustand Store Standards
Store Structure
| Element | Requirement |
|---|---|
| Interface | Define typed state + actions interface |
| State | Group related state together |
| Actions | Define all mutations as functions |
| Naming | use[Domain]Store convention |
Store Design Principles
| Principle | Description |
|---|---|
| Single responsibility | One store per domain (projects, UI, settings) |
| Flat structure | Avoid deeply nested state |
| Immutable updates | Always return new objects |
| Colocated actions | Keep actions inside store definition |
Selector Best Practices
Selection Rules
| Rule | Reason |
|---|---|
| Select minimal data | Reduces re-renders |
Use shallow for objects | Prevents unnecessary updates |
| Memoize derived data | Use useMemo for computed values |
| Avoid selecting entire store | Causes re-render on any change |
Selector Patterns
| Pattern | Use Case |
|---|---|
| Single value | (state) => state.count |
| Multiple values | (state) => ({ a: state.a, b: state.b }), shallow |
| Derived value | useMemo outside store |
Middleware Usage
| Middleware | Purpose | When to Use |
|---|---|---|
persist | LocalStorage persistence | User preferences, settings |
devtools | Redux DevTools integration | Development debugging |
immer | Immutable updates | Complex nested state |
subscribeWithSelector | Granular subscriptions | Performance optimization |
Store Organization
File Structure
code
src/stores/ ├── index.ts # Re-exports all stores ├── projectStore.ts # Domain-specific store ├── uiStore.ts # UI state (modals, panels) └── settingsStore.ts # User preferences
Store Separation Guidelines
| Store Type | Contains |
|---|---|
| Domain store | Business entities, selections |
| UI store | Modal states, panel visibility, loading |
| Settings store | User preferences, persisted config |
Performance Guidelines
DO
- •Select only needed state slices
- •Use
shallowequality for object selections - •Define actions inside store (stable references)
- •Split large stores by domain
- •Use
subscribeWithSelectorfor side effects
DON'T
- •Select entire store object
- •Create new objects in selectors without
shallow - •Put derived/computed state in store
- •Call actions during render phase
- •Create deeply nested store structure
Anti-Patterns
| Anti-Pattern | Problem | Solution |
|---|---|---|
| Giant store | Hard to maintain, performance issues | Split by domain |
| Computed in store | Stale data, extra complexity | Use useMemo |
| Prop drilling | Bypasses store benefits | Use store directly |
| Store in useState | Loses reactivity | Use store hook |
| No TypeScript | Runtime errors | Define interfaces |
Decision Matrix
| Scenario | Recommended Solution |
|---|---|
| Form input state | useState |
| Modal open/close | useState or UI store |
| Selected item (shared) | Domain store |
| User preferences | Persisted store |
| API response data | Store + service function |
| Computed/derived data | useMemo from store values |
| Global loading state | UI store |