⚛️ React Q65 / 113

What is useTransition?

AI-Powered Answer ✓ Answered

The `useTransition` hook in React allows you to mark certain UI updates as 'transitions,' differentiating them from urgent updates. This helps keep your application responsive by allowing React to prioritize urgent updates (like typing in an input) over less urgent ones (like fetching search results).

What is `useTransition`?

useTransition is a React hook introduced to improve the user experience for UIs that might otherwise feel slow or janky when performing non-urgent state updates. It returns two values: isPending (a boolean indicating if a transition is active) and startTransition (a function to wrap your non-urgent state updates).

When you wrap a state update within startTransition, React understands that this update can be interrupted or delayed if a more urgent update (like user input) occurs. This allows React to keep the UI interactive, showing a pending state if necessary, without blocking the main thread for long-running computations or data fetching.

Why use `useTransition`?

Before useTransition, expensive state updates could make the UI freeze or feel unresponsive. For example, typing into a search input that immediately filters a large list could lead to a noticeable delay between key presses and screen updates. This is because React would treat all updates with the same priority.

useTransition addresses this by allowing you to tell React, 'This update is important, but it's not urgent. If something more critical happens, you can show the old state for a bit and then eventually transition to this new state.' This significantly enhances the perceived performance and responsiveness of complex UIs.

How to use `useTransition`

You typically use useTransition by calling it at the top level of your functional component. It returns an isPending boolean and a startTransition function. You then wrap the state update that you want to mark as a transition inside the startTransition callback.

jsx
import React, { useState, useTransition } from 'react';

function SearchableList() {
  const [query, setQuery] = useState('');
  const [deferredQuery, setDeferredQuery] = useState('');
  const [isPending, startTransition] = useTransition();

  const handleChange = (e) => {
    const newQuery = e.target.value;
    setQuery(newQuery); // Urgent update: immediately update input field

    startTransition(() => {
      // Non-urgent update: defer updating the filtered list
      setDeferredQuery(newQuery);
    });
  };

  const filteredItems = useMemo(() => {
    // Simulate expensive filtering
    return Array(10000).fill(null).map((_, i) => `Item ${i}`).filter(item =>
      item.toLowerCase().includes(deferredQuery.toLowerCase())
    );
  }, [deferredQuery]);

  return (
    <div>
      <input type="text" value={query} onChange={handleChange} />
      {isPending && <span>Loading...</span>}
      <ul>
        {filteredItems.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

In this example, typing into the input (setQuery) is an urgent update, so the input field updates instantly. The filtering logic (setDeferredQuery) is wrapped in startTransition, making it a non-urgent update. While isPending is true (meaning the transition is ongoing), a 'Loading...' message can be shown, but the UI remains responsive to further user input.