Avoiding Context Re-render Pitfalls
Context is easy to adopt and easy to misuse. The most common production problem is a single “app context” whose every update re-renders half the tree. Here are the patterns that fix it. Each fix below reduces React context re-render cost, and the React docs on useContext explain why consumers re-render.
1. The problem
const AppContext = createContext(null);
function AppProvider({ children }) {
const [user, setUser] = useState(null);
const [cart, setCart] = useState([]);
const [theme, setTheme] = useState('light');
return (
<AppContext.Provider value={{ user, setUser, cart, setCart, theme, setTheme }}>
{children}
</AppContext.Provider>
);
}
Two issues:
- The
valueobject is recreated on every render, so consumers re-render even when nothing changed. - Adding an item to the cart re-renders every component that reads
userorthemefrom this context.
2. Fix 1: memoize the value
const value = useMemo(() => ({ user, setUser }), [user]);
This stops re-renders caused by the Provider’s parent re-rendering, but not those caused by unrelated fields changing.
3. Fix 2: split contexts by concern
One context per independently-changing piece of state: AuthContext, CartContext, ThemeContext. A cart update now only re-renders cart consumers.
