Hint
In a Provider, wrap the value in useMemo: <Ctx.Provider value={useMemo(() => ({user, login}), [user])}> — this prevents all consumers from re-rendering on every parent render.
let ctxRenders = 0;
function simulate(getContextValue, numRenders) {
let prevValue = null;
for (let i = 0; i < numRenders; i++) {
const newValue = getContextValue();
if (newValue !== prevValue) {
ctxRenders++;
}
prevValue = newValue;
}
}
let user = { name: 'Alice' };
// Unstable: new object every render
simulate(() => ({ user, login: () => {} }), 5);
console.log(ctxRenders); // 5 re-renders (new obj every time)
// Stable: memoized — same reference if user unchanged
ctxRenders = 0;
const stableValue = { user, login: () => {} }; // created once
simulate(() => stableValue, 5);
console.log(ctxRenders); // 1 (only first render)5 1
Explanation: Unstable: {} creates new object each call → 5 different references → 5 re-renders. Stable: same reference every time → only the first render differs from null.
Key Insight: In a Provider, wrap the value in useMemo: