The same mechanism as a transition, applied to a value rather than to an update, which is what a component receiving a prop needs.
function Results({ query }) {
const deferred = useDeferredValue(query)
const stale = query !== deferred
return (
<div style={{ opacity: stale ? 0.6 : 1 }}>
<ExpensiveList query={deferred} />
</div>
)
}
// and the memo that makes it work: without it, the child
// re-renders anyway and the deferral buys nothing.
const ExpensiveList = memo(function ExpensiveList({ query }) { ... })
The memo is not optional and is the part that gets left out — deferring a value only helps if the expensive child skips rendering when the value has not changed. Comparing the current and deferred values gives a stale flag for free, which is a better loading indicator than a spinner because the previous content stays readable.