Part 43: React 18 Concurrency: useTransition & useDeferredValue

Part 43 Technology Updated September 12, 2026

Part 43: React 18 Concurrency: useTransition & useDeferredValue

React 18 introduced Concurrent Rendering, allowing React to pause and resume rendering tasks to keep user interactions (typing, clicking) instantaneous even during heavy calculations.


1. Urgent Updates vs. Non-Urgent Transitions

  • Urgent updates: Typing in an input, clicking a toggle button. Must reflect immediately.
  • Transition updates: Transitioning between views, filtering a 10,000-item chart. Can afford slight delay without feeling broken.

2. Using useTransition

import { useState, useTransition } from 'react';

export default function FilterableList({ heavyItemList }) {
  const [searchTerm, setSearchTerm] = useState('');
  const [filteredList, setFilteredList] = useState(heavyItemList);
  const [isPending, startTransition] = useTransition();

  const handleSearch = (e) => {
    const query = e.target.value;

    // Urgent: Update input text immediately so typing feels instant
    setSearchTerm(query);

    // Non-urgent transition: Wrap heavy calculation
    startTransition(() => {
      const filtered = heavyItemList.filter(item => 
        item.name.toLowerCase().includes(query.toLowerCase())
      );
      setFilteredList(filtered);
    });
  };

  return (
    <div>
      <input 
        type="text" 
        value={searchTerm} 
        onChange={handleSearch} 
        placeholder="Type to filter..." 
      />
      {isPending && <p className="text-gray-400">Updating list results...</p>}

      <ul>
        {filteredList.map(item => <li key={item.id}>{item.name}</li>)}
      </ul>
    </div>
  );
}

3. Using useDeferredValue

When you receive a value via props that triggers heavy rendering, useDeferredValue defers updating child components until more urgent tasks finish:

import { useDeferredValue } from 'react';

export default function SearchResults({ query }) {
  const deferredQuery = useDeferredValue(query);

  return (
    <div style={{ opacity: query !== deferredQuery ? 0.6 : 1 }}>
      <HeavyComponent query={deferredQuery} />
    </div>
  );
}

Key Takeaways

  • Concurrency enables non-blocking user interfaces.
  • Use useTransition to mark heavy state updates as interruptible transitions.
  • Use useDeferredValue to delay re-rendering expensive child components.

In Part 44, we preview React 19 Actions and Modern Form APIs!