Jun 15, 2026
Future-proof components
useMemo is a performance hint, not a guarantee. React is free to throw the cached value away whenever it wants, and increasingly it does, during hot reloads, for offscreen content, or under future optimizations. That is fine when you use it for speed. It is a bug when you use it for correctness.
The fragile assumption
Each user gets a stable avatar gradient derived from their id. If the gradient is regenerated, the color visibly changes, which looks broken.
function Avatar({ user }) {
const gradient = useMemo(
() => generateGradient(user.id),
[user.id],
)
return <div style={gradient}>{user.initials}</div>
}
generateGradient may include some randomness or expensive hashing. If React drops the memo and recomputes, the user’s color shifts under them. You were relying on useMemo to persist a value, which it never promised to do.
The fix
When correctness depends on a value sticking around, store it in state. State is a guarantee. Recompute it explicitly only when the input that matters actually changes.
function Avatar({ user }) {
const [gradient, setGradient] = useState(() => generateGradient(user.id))
const [prevId, setPrevId] = useState(user.id)
if (user.id !== prevId) {
setPrevId(user.id)
setGradient(generateGradient(user.id))
}
return <div style={gradient}>{user.initials}</div>
}
The gradient now persists for the lifetime of the user and changes only when the id does. Use useMemo for speed, use state for promises. None of these are edge cases anymore. They are the conditions your components already ship into, so it is worth building for them from the start.