State Management
Decision matrix for choosing the correct state management tool. Using the wrong tool is a code review blocker.
Decision Matrix
| Data Type | Tool | Location |
|---|---|---|
| Server entities (CRUD) | React Query | frontend/src/lib/queries/ |
| Global auth/preferences | Zustand + localStorage | frontend/src/store/ |
| URL-shareable UI state | URL state hooks | frontend/src/hooks/url-state/ |
| Form fields | react-hook-form + Zod | Inline in form components |
| Transient UI (tooltips, dropdowns) | useState | Component-local |
Anti-Patterns (NEVER)
useStatefor server data — use React Query PatternuseContextfor global state — use Zustand- Raw
useSearchParams— use URL State Management hooks - Inline
useMutationin components — define inlib/queries/
Zustand Stores
Three stores in frontend/src/store/:
| Store | Purpose |
|---|---|
auth.ts | Current user, JWT token, login state |
projects.ts | Active project selection |
workflow.ts | Workflow engine UI state |
All stores use localStorage persistence for session survival.
Context Providers
Limited to two specialized cases:
| Provider | Purpose |
|---|---|
FormBuilderContext.tsx | Form Builder drag-and-drop state |
ResponsibilityFilterContext.tsx | Cross-component filter coordination |
React Query Client Config
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 10 * 60 * 1000, // 10 minutes garbage collection
refetchOnWindowFocus: false,
},
}See Also
- React Query Pattern — server state details
- URL State Management — URL-synced hooks
- Hooks — custom hook organization
- Frontend Architecture — overall frontend structure
- Component Decomposition — where state hooks live in split components