React 101 - useDeferredValue

React 101 - useDeferredValue

In React, we often encounter scenarios where expensive processing can slow down renders.

To address this, React provides the useDeferredValue hook.

This hook allows us to mark resource-intensive tasks as "low priority," ensuring that more urgent UI updates can proceed smoothly without interruption.

Let’s take a look at an example to understand how this works in practice.

In this example, we have a classic Typeahead component that queries a list of cities from a JSON file.


import React, { useState } from 'react';

import cities from './cities.json'; 

export function Typeahead() {
  const [query, setQuery] = useState('');
  const [suggestions, setSuggestions] = useState([]);

  const filterCities = (input) => {
    if (!input) return [];
    const start = performance.now();
    while (performance.now() - start < 300) {}
    return cities.filter((city) =>
      city.name.toLowerCase().includes(input.toLowerCase())
    );
  };

  React.useEffect(() => {
    const results = filterCities(query);
    setSuggestions(results);
  }, [query]);

  const handleChange = (event) => {
    setQuery(event.target.value);
  };

  return (
    <div>
      <input
        type='text'
        value={query}
        onChange={handleChange}
        placeholder='Search for cities...'
      />
      <ul>
        {suggestions.map((city, index) => (
          <li key={index}>
            <strong>{city.name}</strong>
            <br />
            <small>{city.country}</small>
          </li>
        ))}
      </il>
    </div>
  );
}
        

You'll notice this section of the code

    const start = performance.now();
    while (performance.now() - start < 300) {}        

Here, we’re simulating a computationally intensive operation that could slow down rendering and create a janky user experience.

The result is a sluggish and choppy experience, as both the suggestions list rendering and the input field updates happen simultaneously. When the filtering process is resource-intensive, it blocks the main thread, causing delays in the UI and unresponsiveness during typing.


Article content

In order to fix this, we can utilize the useDeferredValue hook.

 const [query, setQuery] = useState('');
 const [suggestions, setSuggestions] = useState([]);
 const deferredQuery = useDeferredValue(query);
....
  React.useEffect(() => {
    const results = filterCities(deferredQuery);
    setSuggestions(results);
  }, [deferredQuery]);
        

This marks the deferred query as low-priority, telling React to prioritize more urgent updates (like user interactions) and defer the update of this part of the UI until after higher-priority tasks are completed. This helps prevent blocking the main thread and ensures smoother, more responsive rendering during fast updates.

The end result is a much smoother user experience, as the input field can render without being blocked by the suggestions list.

Article content


To view or add a comment, sign in

More articles by William Henshaw

  • Debugging React 101 - Profiler

    Another valuable tool for optimizing and debugging our React application is the Profiler. This feature, part of React…

  • Debugging React 101 - Getting started

    React provides a set of valuable tools to help us debug and optimize our applications. But where should we start? The…

  • Defining functions in Javascript

    Function Declarations Defined with the function keyword at the start. Hoisted and can be called before defined in code.

Explore content categories