Hooks
useContext & avoiding re-render storms
Context for shared state, its performance trap, and how to split it.
The Context API shares values across the tree without prop drilling. createContext + Provider publish a value; useContext reads it anywhere below.
Context is a building intercom; one channel for everything means every room reacts to every announcement — give each concern its own channel.
Key concepts
1
The performance trap: every consumer re-renders whenever the provider’s value changes — and passing a fresh object literal each render changes it every time. Memoize the value, and split contexts so unrelated consumers do not re-render together (e.g. separate AuthContext and ThemeContext).
The performance trap:split contextsAuthContextThemeContext
2
A common pattern pairs context with useReducer to expose state + dispatch as a lightweight store, keeping dispatch stable so action-only consumers never re-render.
useReducerdispatch
3
Pitfall: using one giant "AppContext" for everything, causing app-wide re-renders. Interview angle: "why did adding context slow the app?" — unmemoized value + monolithic context; fix by splitting and memoizing, or reach for an external store.
Pitfall:Interview angle:
jsx
const AuthContext = createContext(null);
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const value = useMemo(() => ({ user, setUser }), [user]); // stable
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
const useAuth = () => useContext(AuthContext);