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:

  1. The Urgent Render: React immediately re-renders the component using the updated original state, but keeps the useDeferredValue at its previous, older value. This allows the primary UI (like an input field) to update instantly without lag.
  2. 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