How to Update useDeferredValue Hook in React
This article explains how to update and work with the
useDeferredValue Hook in React to optimize application
performance. You will learn the underlying mechanism of how deferred
values update, how to trigger these updates by modifying the source
state, and a practical implementation example to prevent UI lagging
during heavy renders.
Unlike standard React hooks like useState or
useReducer, the useDeferredValue Hook does not
provide a direct setter function to update its value. Instead, it
accepts a single state or prop value as an argument and automatically
updates itself in the background when the source value changes.
To update a deferred value, you must update the original state value passed into the Hook.
How the Update Cycle Works
When the source state updates, React handles the rendering process in two distinct steps to keep the user interface responsive:
- The Urgent Render: React immediately re-renders the
component using the updated original state, but keeps the
useDeferredValueat its previous, older value. This allows the primary UI (like an input field) to update instantly without lag. - The Deferred Render: In the background, React schedules a low-priority re-render with the new deferred value. If the user triggers another update before this background render finishes, React abandons the stale background render and starts a new one with the latest value.
Code Implementation
Here is a straightforward example demonstrating how to update a deferred value using an input field and a heavy list component:
import { useState, useDeferredValue, memo } from 'react';
function App() {
const [text, setText] = useState('');
// The deferred value is linked to the 'text' state
const deferredText = useDeferredValue(text);
return (
<div>
{/* Updating 'text' automatically schedules an update for 'deferredText' */}
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="Type to search..."
/>
<p>Immediate input: {text}</p>
<SlowList text={deferredText} />
</div>
);
}
// Memoizing the slow component ensures it only re-renders when the deferred value changes
const SlowList = memo(function SlowList({ text }) {
const items = [];
for (let i = 0; i < 250; i++) {
items.push(<li key={i}>{text} Item {i}</li>);
}
return <ul>{items}</ul>;
});
export default App;Key Considerations for Updating Deferred Values
- Memoization is Required: For
useDeferredValueto work effectively, the child component receiving the deferred value must be wrapped inReact.memo. This prevents the slow component from re-rendering during the urgent phase when the deferred value has not yet changed. - Primitive and Object Values: React uses
Object.isto compare the previous and new values passed touseDeferredValue. If you pass a newly created object on every render, the Hook will trigger an update on every render. To prevent this, wrap the source object inuseMemo.