Advanced State Management 🧠
Large apps juggle UI state, external data, and complex flows. Choose patterns that match the problem instead of defaulting to a single tool.
1) State Machines (Optional) ⚙️
- Represent UI as finite states with explicit transitions.
- Libraries: XState, Robot, or custom reducers.
const machine = {
idle: { START: "loading" },
loading: { RESOLVE: "success", REJECT: "error" },
success: { RESET: "idle" },
error: { RETRY: "loading" }
};- Benefits: predictable transitions, visualizable flows, built-in guards.
- Trade-off: learning curve and boilerplate.
2) External Stores & useSyncExternalStore 🧵
When state lives outside React (MobX, custom observable), use useSyncExternalStore for concurrent safety.
import { useSyncExternalStore } from "react";
function useStore(selector) {
return useSyncExternalStore(store.subscribe, () => selector(store.getSnapshot()));
}- Ensures React reads a consistent snapshot during render.
- Necessary for libraries integrating with React 18+ concurrency.
3) Library Tradeoffs 🧰
| Library | Strengths | Considerations |
|---|---|---|
| Redux Toolkit | Opinionated Redux setup, immutable logic, devtools | Best for large teams needing strict patterns |
| Zustand | Tiny API, hooks per slice, no boilerplate | Mutation risk if not careful; minimal structure |
| Jotai | Atom-based, derives state via hooks | Many atoms can become scattered; best for modular state |
- Evaluate based on team size, debugging needs, and architectural constraints.
4) Server State (TanStack Query / SWR) 🌐
Server state differs from local UI state:
- Lives on server, fetched via HTTP.
- Can become stale; requires caching/invalidation strategies.
TanStack Query
- handles caching, retries, and background refetching.
- declarative API:
useQueryanduseMutation.
const { data, status } = useQuery({
queryKey: ["projects"],
queryFn: () => fetch("/api/projects").then(res => res.json()),
staleTime: 60_000
});SWR
- Stale-while-revalidate pattern; simple API
useSWR(key, fetcher). - Great for lightweight caching needs.
🧠 Let server-state libraries own asynchronous data while React state focuses on UI interactions.
Key Takeaways ✅
- State machines clarify complex flows when simple flags fail.
useSyncExternalStorebridges React with external data sources safely.- Redux Toolkit, Zustand, and Jotai target different scales and ergonomics.
- TanStack Query / SWR manage server state lifecycles, freeing you from manual caching.
Recap 🔄
Map state solutions to the problem space: finite machines for complex flows, external stores for shared data, curated libraries for app-wide coordination, and server-state helpers for remote data. Mixing patterns thoughtfully keeps state predictable and maintainable.
Last updated on