Concurrent Transitions: React 18
Concurrent Transitions: React 18
React 18 introduced concurrent rendering the ability to prepare multiple UI versions in parallel. The useTransition hook and startTransition function let you mark state updates as non-urgent, keeping the UI responsive during expensive re-renders.
A concurrent transition defers a state update to be processed at lower priority, allowing React to continue rendering the current UI and handling urgent updates (like typing) without interruption.
1. useTransition
Returns a boolean isPending flag and a startTransition function. Updates inside startTransition are treated as non-urgent.
SearchFilter.jsx
JSX (React 18)
import { useState, useTransition } from 'react'; export function SearchFilter({ items }) { const [query, setQuery] = useState(''); const [filtered, setFiltered] = useState(items); const [isPending, startTransition] = useTransition(); function handleChange(e) { const val = e.target.value; setQuery(val); // urgent — updates input immediately startTransition(() => { // non-urgent — expensive filter deferred setFiltered(items.filter(item => item.toLowerCase().includes(val.toLowerCase()) )); }); } return ( <div> <input value={query} onChange={handleChange} placeholder="Search…" /> {isPending && <span>Updating…</span>} <ul> {filtered.map(item => <li key={item}>{item}</li>)} </ul> </div> ); }
2. useDeferredValue
Similar to useTransition but works when you don’t own the state update (e.g. a prop from a parent). Returns a deferred copy of the value that lags behind during transitions.
DeferredList.jsx
JSX (React 18)
import { useDeferredValue, memo } from 'react'; // Expensive child — memo prevents re-render unless deferredQuery changes const SlowList = memo(({ query }) => { const items = heavyFilter(query); // expensive operation return <ul>{items.map(i => <li key={i}>{i}</li>)}</ul>; }); export function DeferredSearch({ query }) { const deferredQuery = useDeferredValue(query); const isStale = query !== deferredQuery; return ( <div style={{ opacity: isStale ? 0.5 : 1, transition: 'opacity 0.2s' }}> <SlowList query={deferredQuery} /> </div> ); }
Note: Concurrent transitions are not visual animations, they are a scheduling mechanism. They prevent the UI from freezing during heavy state updates. Combine with visual transitions (opacity fade on isPending) to give users feedback.
DoFollow Links:
