intermediate 8 min read
State Management Patterns
Modern frontend state management separates concerns into local component state, server cache (TanStack Query), URL state (search params), and lightweight client stores (Zustand) — each optimized for different access patterns.
Why it matters in interviews
Senior/Lead interviews heavily test whether you understand that not all state belongs in a global store. The ability to architect state by access pattern (local vs shared, client vs server, URL-driven) is a top differentiator.
Visual & Interactive Explanation
State Management Decision Matrix
Local State
useState / useReducer
ScopeSingle component
PersistenceNone (re-mount resets)
Re-renderOnly this component
Zustand
Atomic client store
ScopeCross-component
PersistenceOptional middleware
Re-renderSelector subscribers only
TanStack Query
Server cache
ScopeAPI responses
PersistenceCache with TTL
Re-renderQuery key subscribers
Code Examples & Implementation
Zustand Store with Selectors
import { create } from "zustand";
interface AppStore {
count: number;
name: string;
increment: () => void;
setName: (name: string) => void;
}
const useAppStore = create<AppStore>((set) => ({
count: 0,
name: "Alice",
increment: () => set((s) => ({ count: s.count + 1 })),
setName: (name) => set({ name }),
}));
// Only re-renders when count changes
function Counter() {
const count = useAppStore((s) => s.count);
return <p>{count}</p>;
}
// Only re-renders when name changes
function NameDisplay() {
const name = useAppStore((s) => s.name);
return <p>{name}</p>;
}TanStack Query — Server Cache with Background Refetch
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
function TodoList() {
const { data, isLoading, error } = useQuery({
queryKey: ["todos"],
queryFn: () => fetch("/api/todos").then((r) => r.json()),
staleTime: 30_000, // fresh for 30s
gcTime: 5 * 60_000, // garbage-collect after 5min unused
});
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (newTodo: string) =>
fetch("/api/todos", {
method: "POST",
body: JSON.stringify({ title: newTodo }),
}),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["todos"] });
},
});
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return <ul>{data.map((t: any) => <li key={t.id}>{t.title}</li>)}</ul>;
}URL State for Shareable Filters
import { useSearchParams } from "next/navigation";
function ProductFilters() {
const searchParams = useSearchParams();
const category = searchParams.get("category") || "all";
const sort = searchParams.get("sort") || "newest";
// URL: /products?category=shoes&sort=price
// Shareable, bookmarkable, back-button friendly
return (
<div>
<p>Category: {category}</p>
<p>Sort: {sort}</p>
</div>
);
}Interview-Ready Answers
Use local state for component-scoped values, TanStack Query for server data caching, URL params for shareable filters, and Zustand for shared client state.
Follow-up Questions & Deep Dives
🎯 Code Output — What Does This Print?
Question 1hard
const ThemeCtx = React.createContext("light");
function App() {
const [theme, setTheme] = useState("light");
return (
<ThemeCtx.Provider value={theme}>
<Header />
<MemoizedContent />
<button onClick={() => setTheme("dark")}>Toggle</button>
</ThemeCtx.Provider>
);
}
const MemoizedContent = React.memo(function Content() {
console.log("Content render");
return <p>Content</p>;
});
function Header() {
const theme = useContext(ThemeCtx);
console.log("Header render:", theme);
return <h1>{theme}</h1>;
}
// User clicks Toggle. Does MemoizedContent re-render?Common Mistakes & Anti-Patterns
- Storing server data in Redux instead of a dedicated cache layer (TanStack Query)
- Using React Context for high-frequency state changes, causing all consumers to re-render
- Not using selector functions with Zustand, subscribing to the entire store
- Duplicating URL-representable state (filters, pagination) in client state instead of search params
Real-World Architectural Scenario
A dashboard has filters (date range, category, status), a data table with pagination, and a user preferences panel. How do you architect the state?
Rate Your Readiness
Rate how comfortably you can explain this in an interview to update your global readiness gauge:
Rate your confidence: