useDeferredValue
Defers updating a part of the UI to keep the rest responsive. Returns a value that may lag behind during urgent updates, allowing non-critical UI to render at a lower priority.
Signature
const deferredValue = useDeferredValue<T>(value: T, initialValue?: T)Parameters
| Parameter | Type | Description |
|---|---|---|
| value | T | The value you want to defer. When value changes, React first renders with the old deferred value, then re-renders in the background with the new value. |
| initialValue | T | Optional initial value used during the first render (React 19+). When provided, the component renders with this value initially, then re-renders with the actual value. |
Return Value
The deferred value. During urgent updates it returns the previous value; the updated value catches up in a background render.
Examples
import { useState, useDeferredValue, useMemo } from 'react';
function SearchPage({ items }: { items: string[] }) {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
const isStale = query !== deferredQuery;
const results = useMemo(
() => items.filter(item => item.toLowerCase().includes(deferredQuery.toLowerCase())),
[items, deferredQuery],
);
return (
<div>
<input
value={query}
onChange={e => setQuery(e.target.value)}
placeholder="Search..."
/>
<div style={{ opacity: isStale ? 0.6 : 1, transition: 'opacity 0.2s' }}>
{results.map(item => <div key={item}>{item}</div>)}
</div>
</div>
);
}import { useState, useDeferredValue } from 'react';
function Dashboard({ data }: { data: number[] }) {
const [range, setRange] = useState(100);
const deferredRange = useDeferredValue(range);
const chartData = data.slice(0, deferredRange);
return (
<div>
<input
type="range"
min={10}
max={data.length}
value={range}
onChange={e => setRange(Number(e.target.value))}
/>
<p>Showing {deferredRange} of {data.length} points</p>
<ExpensiveChart data={chartData} />
</div>
);
}import { useState, useDeferredValue, memo } from 'react';
const SlowList = memo(function SlowList({ text }: { text: string }) {
const items = [];
for (let i = 0; i < 500; i++) {
items.push(
<li key={i} style={{
color: text && `item ${i}`.includes(text) ? '#3b82f6' : '#888',
}}>
Item {i}
</li>
);
}
return <ul>{items}</ul>;
});
function FilterableList() {
const [text, setText] = useState('');
const deferredText = useDeferredValue(text);
return (
<div>
<input value={text} onChange={e => setText(e.target.value)} />
<SlowList text={deferredText} />
</div>
);
}Common Pitfalls
Using useDeferredValue for values that don't trigger expensive renders — the overhead isn't justified.
Not combining with React.memo or useMemo — without memoization the deferred render still does the same work.
Expecting the deferred value to debounce — it doesn't delay a fixed time, it defers based on React's scheduling.
Using it for data fetching timing — useDeferredValue is for rendering priority, not network request scheduling.
Understanding useDeferredValue
useDeferredValue is a concurrent rendering hook that allows you to mark a value as non-urgent, enabling React to prioritize more critical updates. When a value changes, React first renders with the old deferred value (keeping the UI responsive), then re-renders in the background with the new value. This is particularly effective for expensive renders triggered by user input, like filtering large lists or updating complex visualizations.
The hook works in tandem with React's concurrent rendering features. When you type in a search input, React can immediately update the input field (urgent) while deferring the expensive list filtering (non-urgent). The user sees their keystrokes reflected instantly, while the search results catch up in the background. This creates a smooth, responsive experience even with computationally heavy renders.
An important pattern is checking whether the deferred value has caught up by comparing it with the current value. When query !== deferredQuery, you know the displayed results are stale and can show a visual indicator like reduced opacity or a loading spinner. This communicates to the user that results are updating without blocking their interaction.
For useDeferredValue to provide a real benefit, the deferred render must be skippable — meaning the component using the deferred value should be memoized with React.memo or the computation should be wrapped in useMemo. Without memoization, React still has to do the full rendering work even though it has the old value available. The combination of useDeferredValue with memoization is what creates the actual performance improvement.
Related Hooks
useTransitionMarks a state update as non-urgent, allowing the UI to remain responsive during the transition. Returns a pending flag and a function to wrap low-priority updates.
useMemoCaches the result of an expensive computation between re-renders, recomputing only when dependencies change.
useCallbackReturns a memoized version of a callback function that only changes when its dependencies change. Prevents unnecessary re-renders of child components that receive callbacks as props.
More Performance Hooks
Explore All React Hooks
Browse our complete reference of 19 React hooks with signatures, examples, pitfalls, and in-depth explanations.