Every component that reads a context re-renders when the provider receives a different value, even if only part of the value changed. The reason is that React compares the old and new values with Object.is, and an inline object or function gets a new identity on every render. You can reduce the extra work by stabilizing the value.
How context re-renders work
React re-renders all readers of a context when the provider receives a different value. It decides whether the value changed by comparing the previous and next values with Object.is, which checks identity for objects and functions rather than their contents.
<AuthContext value={{ user, login }}>
<Page />
</AuthContext>This inline object is a different object on every App render, even when user is unchanged. React treats that as a changed value and re-renders every component that reads AuthContext.
Why the value changes identity
The provider creates the value object during render. A new render runs the code again, so a fresh object and a fresh function appear even if the data they wrap stayed the same.
The login function is also recreated each render. A function is compared by identity too, so passing it inline contributes to the same problem.
Stabilize the value with useMemo
Wrap the object in useMemo so it only changes when its dependencies change. The provider then reuses the same object across renders when nothing important moved.
import { useMemo, useState } from "react";
export default function App() {
const [user, setUser] = useState(null);
const value = useMemo(() => ({ user, setUser }), [user]);
return (
<AuthContext value={value}>
<Page />
</AuthContext>
);
}Now the context value keeps the same identity until user changes, so readers skip re-renders that only repeat the same data.
Stabilize functions with useCallback
A function passed through the value has the same identity problem. Wrap it in useCallback so it stays the same object until its dependencies change.
import { useCallback, useMemo, useState } from "react";
export default function App() {
const [user, setUser] = useState(null);
const login = useCallback((response) => {
setUser(response.user);
}, []);
const value = useMemo(() => ({ user, login }), [user, login]);
return (
<AuthContext value={value}>
<Page />
</AuthContext>
);
}The login function now keeps the same identity across renders, and value only changes when user or login changes. Keep the dependency array accurate. An empty array means the function never changes, which is fine only when it captures no changing values.
What memo cannot do
React.memo skips a re-render when a component receives the same props. It does not shield a component from a changed context value, because context flows outside the props channel. If a component calls useContext and the value changes, it re-renders regardless of memoization.
When to optimize
Do not memoize context values by habit. Measure the render problem first, then apply useMemo and useCallback only when a context value updates often and many readers do expensive work. For a theme that changes rarely, the plain inline object is fine.
What to learn next
Splitting one large context into smaller ones removes re-renders without memoization. See how to split React context by responsibility. To wire a value to state in the first place, see how to update context values from child components.
Rune AI
Key Insights
- Context readers re-render when the value changes identity.
- React compares values with Object.is, not deep equality.
- Inline objects and functions change identity on every render.
- useMemo and useCallback keep the value stable.
- React.memo does not prevent context-driven re-renders.
Frequently Asked Questions
Does React.memo stop context re-renders?
When does React decide a context value changed?
Should I always memoize context values?
Conclusion
Context re-renders every component that reads it when the provider passes a new value. Stabilize the value with useMemo and useCallback when that work is actually measured as a problem, and remember that React.memo does not shield context readers.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.