The Problem
Imagine you're building a search feature for a list of 2,000 products. Every time a user types a letter, your app filters the entire list and re-renders it. What happens? The input lags. The user's typing feels sluggish and frustrating.
This is a common problem when dealing with heavy updates in React. What if we could tell React: "Hey, updating this list is important, but keeping the input smooth is MORE important"?
That's exactly what useTransition does.
What is useTransition?
useTransition is a React hook (introduced in React 18) that lets you mark certain updates as non-urgent. This means React can prioritize user interactions (like typing) over heavy rendering tasks (like filtering a huge list).
Basic Syntax
const [isPending, startTransition] = useTransition();
-
startTransition: A function that wraps non-urgent updates -
isPending: A boolean that tells you if the transition is still in progress (useful for showing loading states)
How It Works
React categorizes updates into two types:
- Urgent updates: User interactions like typing, clicking, hovering
- Non-urgent updates: Heavy operations like filtering, sorting, complex calculations
When you wrap an update in startTransition, you're telling React: "This can wait. Keep the UI responsive first."
Real Example: Filtering a Large List
Let's build a practical example. We have 2,000 products and want to filter them as the user types.
The Data
// hugeList.ts
export interface Product {
id: number;
name: string;
}
export const hugeList: readonly Product[] = Array.from(
{ length: 2000 },
(_, i) => ({
id: i,
name: `Product ${i}`,
})
);
Without useTransition (Laggy)
function App() {
const [value, setValue] = useState("");
const [filteredProducts, setFilteredProducts] = useState(hugeList);
const handleChange = (newValue) => {
setValue(newValue);
// This blocks the input!
setFilteredProducts(
hugeList.filter((item) =>
item.name.toLowerCase().includes(newValue.toLowerCase())
)
);
};
return (
<>
<input value={value} onChange={(e) => handleChange(e.target.value)} />
<ProductList items={filteredProducts} />
</>
);
}
Problem: Every keystroke triggers a heavy filter operation that blocks the input.
With useTransition (Smooth)
function App() {
const [value, setValue] = useState("");
const [filteredProducts, setFilteredProducts] = useState([...hugeList]);
const [isPending, startTransition] = useTransition();
useEffect(() => {
startTransition(() => {
setFilteredProducts(
hugeList.filter((item) =>
item.name.toLowerCase().includes(value.toLowerCase())
)
);
});
}, [value]);
return (
<>
<input value={value} onChange={(e) => setValue(e.target.value)} />
{isPending && <p>Filtering...</p>}
<ProductList items={filteredProducts} />
</>
);
}
Result: The input stays smooth! React keeps it responsive while filtering happens in the background.
When to Use useTransition
Perfect for:
- Filtering or sorting large lists (1,000+ items)
- Heavy calculations that slow down the UI
- Complex rendering (charts, graphs, data tables)
- Tab navigation with heavy content
When NOT to Use useTransition
Skip it for:
- Small, fast updates (simple toggles, counters)
- Updates that must happen immediately
- API calls (better handled with loading states and async patterns)
- Animations (use CSS or animation libraries)
Important Limits
useTransition is not magic. It doesn't solve everything:
- 50,000+ DOM elements will still be slow. You need virtualization (like
react-window) - It's not a replacement for
React.memo, lazy loading, or code splitting - It only helps with React updates, not external operations
Best Practices
-
Use only for genuinely heavy updates - Don't wrap everything in
startTransition -
Combine with other optimizations - Use
memo,useMemo, and proper component structure - Show feedback with isPending - Let users know something is happening
- Test with realistic data - 10 items won't show the difference, 2,000 will
Conclusion
useTransition is a powerful tool for building smooth, responsive UIs in React. It's not about making things fasterโit's about making the right things fast (user interactions) and letting the heavy things wait (complex rendering).
๐ป Complete Code
Check out the full working project on my GitHub:
github.com/DavideCannerozzi/react-use-transition-search
Top comments (1)
nice๏ผI am learning react