Learn the concept
State Management
Use Context API for simple, low-frequency state (theme, auth, locale) shared across components. Use Redux (or Redux Toolkit) for complex, frequently-updated state that benefits from middleware, selective subscriptions, time-travel debugging, and predictable update patterns.
Context API — What It Is:
Context is a React feature for passing data through the component tree without prop drilling. It is not a state management solution — it is a dependency injection mechanism. You still need useState or useReducer to actually manage the state; Context just provides a way to share it.
Context API — When It Works Well:
Context API — The Re-Render Problem:
When a context value changes, every component that calls useContext() for that context re-renders — even if the component only uses a small part of the value. There is no built-in way to subscribe to a slice of context.
// If ANY field in this object changes, ALL consumers re-render
const AppContext = createContext({ user: null, theme: 'light', cart: [] });For frequently-changing state (like a shopping cart or real-time data), this causes excessive re-renders.
Redux Toolkit — When It Shines:
Redux Toolkit (RTK) is the modern, official way to use Redux. It provides:
useSelector only re-renders a component when its selected slice of state changesModern Alternatives:
Decision Framework:
| Scenario | Solution | |----------|----------| | Theme, auth, locale | Context + useState | | Form state, UI toggles | Local useState | | Server data (API responses) | TanStack Query or RTK Query | | Moderate shared client state | Zustand | | Complex client state with middleware needs | Redux Toolkit | | Simple atomic state | Jotai or Zustand |
const AppContext = createContext();
function AppProvider({ children }) {
const [user, setUser] = useState(null);
const [theme, setTheme] = useState('light');
const [notifications, setNotifications] = useState([]);
// Every time ANY of these values changes, ALL consumers re-render
const value = { user, setUser, theme, setTheme, notifications, setNotifications };
return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
}
// This component re-renders when notifications change,
// even though it only uses theme!
function ThemeToggle() {
const { theme, setTheme } = useContext(AppContext);
return <button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>{theme}</button>;
}
// Mitigation: Split into separate contexts
const ThemeContext = createContext();
const UserContext = createContext();
const NotificationContext = createContext();
// Now each consumer only re-renders for its own context changesShopping carts with real-time price calculations benefit from Redux or Zustand's selective subscriptions, as Context would re-render the entire checkout page on every cart change.
Theme toggling and language switching are ideal Context use cases — they change infrequently and affect the entire app.
Build the same todo app with Context, Redux Toolkit, and Zustand. Add React DevTools profiling to compare re-render counts.
Create a visualization that shows how many components re-render when a Context value changes vs a Redux selector.