useTransition Hook — UI Updates Without Slowing Down the Interface
useTransition is a React 18 hook that allows React to differentiate between which updates are urgent and which are non-urgent. This way React can prioritize updates that immediately affect the user experience.
For example: a user types in a search input. React needs to simultaneously: 1️⃣ Update the input value (urgent) 2️⃣ Filter hundreds of data items in a list (non-urgent)
Without useTransition, the input might "freeze" or respond slowly. useTransition solves exactly this problem.
🔹 Syntax
const [isPending, startTransition] = useTransition();
- isPending — boolean value indicating whether the non-urgent update is still in progress.
- startTransition(callback) — function where you place the state change that you want to mark as "non-priority".
📍 Example 1 — Fast-Responding Search Input
import React, { useState, useTransition } from 'react';
export default function SearchList() {
const [query, setQuery] = useState('');
const [filtered, setFiltered] = useState([]);
const [isPending, startTransition] = useTransition();
const items = Array.from({ length: 5000 }, (_, i) => `Element ${i + 1}`);
const handleChange = (e) => {
const value = e.target.value;
setQuery(value);
startTransition(() => {
const filteredItems = items.filter((item) =>
item.toLowerCase().includes(value.toLowerCase())
);
setFiltered(filteredItems);
});
};
return (
<div>
<h2>🔎 Filtering Example with useTransition</h2>
<input
type="text"
value={query}
onChange={handleChange}
placeholder="Search..."
/>
{isPending && <p>Loading...</p>}
<ul>
{filtered.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
</div>
);
}
Here React updates the input value immediately, while list filtering is performed within the transition scope without "freezing" the UI. If the filtering process takes a bit longer, React maintains the input update with invisible latency.
📍 Example 2 — Step-by-Step Explanation
setQuery()— executes immediately as urgent updatestartTransition()— starts non-urgent update (filtering)- React first shows the new input value, then only updates the list
isPendingis true until filtering completes
📍 Example 3 — Showing Loading State with isPending
You can use the `isPending` value to display a loader or skeleton.
{isPending ? (
<p>Loading new data...</p>
) : (
<List data={filtered} />
)}
This way React can transition between data more smoothly without visible jank.
📍 Example 4 — Transition + Pagination
This hook is also excellent for pagination or tab-switching, when new page content needs to load without brief UI freeze.
import React, { useState, useTransition } from 'react';
export default function PaginationExample() {
const [page, setPage] = useState(1);
const [isPending, startTransition] = useTransition();
const handlePageChange = (newPage) => {
startTransition(() => {
setPage(newPage);
});
};
return (
<div>
<h3>Page {page}</h3>
<button onClick={() => handlePageChange(page - 1)} disabled={page === 1}>
Previous
</button>
<button onClick={() => handlePageChange(page + 1)}>
Next
</button>
{isPending && <p>Loading next page...</p>}
</div>
);
}
Here the UI never "freezes" when switching between pages. React first displays the action result, then starts the non-urgent update.
⚙️ Best Practices
- Use useTransition for updates that can be slightly delayed.
- Always keep input or UI interaction immediate (urgent update).
- Don't place network requests inside transitions — they should be in async logic.
- Don't use transition for every small update — it won't provide performance gain.
🧠 What React Actually Does
React implements Concurrent Rendering — allowing two rendering processes simultaneously: one priority (urgent), the other in the background (deferred). It "suspends" non-urgent rendering if new urgent actions occur.
This is one of React's major innovations that allows writing responsive UI — without additional throttling or debounce logic.
🎯 Exercise (Try it yourself)
Write a component that:
- Has a search input and a list with 10,000 elements.
- Uses useTransition for filtering.
- Shows a loader when filtering is in progress.
Try the difference without useTransition and see how the input responds. The result is obvious 💨.
📘 Summary
- useTransition — React 18 hook for non-urgent updates.
- Helps create smoother UI without input lag.
- Returns
[isPending, startTransition]. - Apply in filtering, pagination, search, or heavy rendering scenarios.