An Auth Provider passing `{ user, logout, settings }` as inline object. Every render creates a new object reference; React triggers re-render on every consumer. Performance degrades as the app grows.
The vulnerable diff
// context/Auth.tsx
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [settings, setSettings] = useState<Settings | null>(null);
const logout = () => setUser(null);
// BUG: new object every render → all consumers re-render
return (
<AuthContext.Provider value={{ user, logout, settings }}>
{children}
</AuthContext.Provider>
);
}What is wrong
React's context propagation triggers re-render of every consumer whenever the Provider's `value` changes by reference. An inline object literal creates a new reference on every render of the Provider's parent — even if `user`, `logout`, and `settings` haven't changed. Every consumer re-renders unnecessarily. The fix is `useMemo` for the value (preserving reference when dependencies are unchanged), or splitting into multiple contexts so unrelated consumers don't re-render together.
The attack
Performance impact:
100 consumers under <AuthProvider>.
Parent re-renders 60 times/sec (e.g., parent has a setState somewhere).
Without memo: 60 * 100 = 6000 unnecessary re-renders/sec.
With memo: 0 (until user/logout/settings change).Common cause of mysterious React performance issues.
Mesrai's review comment
mesraipilot · Bot · reviewed 1 min ago
[mesrai] [code-review] [Performance] [React-Context-Re-render] [medium]
`value={{ ... }}` creates a new object every render. All consumers
re-render every time the Provider's parent renders.
useMemo the value:
const value = useMemo(
() => ({ user, logout, settings }),
[user, logout, settings]
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
Also useCallback for functions inside the value:
const logout = useCallback(() => setUser(null), []);
For high-traffic contexts, split: separate Provider for state vs
actions so action-only consumers don't re-render on state changes:
<UserStateContext.Provider value={user}>
<UserActionsContext.Provider value={actions}>
{children}The fix
// context/Auth.tsx — fixed
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [settings, setSettings] = useState<Settings | null>(null);
const logout = useCallback(() => setUser(null), []);
const value = useMemo(
() => ({ user, logout, settings }),
[user, logout, settings]
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}Memoized value preserves reference. useCallback for the function. Re-renders only when actual data changes.
Why human review missed it
Inline Provider value is one of the most common React performance bugs. Mesrai catches every Provider with an inline-literal value.
Related rules + further reading
Mesrai rule pack: performance/react-context-value-memo — flags inline object/array on Context.Provider value.
React docs: useMemo + useCallback for context values.
Common React perf issue.
Takeaway
useMemo Provider values. useCallback functions inside. Mesrai catches the inline pattern.