Suggest an editImprove this articleRefine the answer for “What is "startTransition()"?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`startTransition(callback)`** tells React that the state updates inside `callback` can be deferred (they have low priority). **Key point:** it is a way to tell React "do this update, but don't rush, render what matters for UX first (for example, text input)".Shown above the full answer for quick recall.Answer (EN)Image## What `startTransition()` is > `startTransition(callback)` tells React > that the state updates inside `callback` **can be deferred** (they have *low priority*). In simpler terms: > It's a way to tell React: > "Do this update, but **don't rush**, > render what matters for UX first (for example, text input)." --- ## Example without `startTransition` ```javascript function Search() { const [query, setQuery] = useState(''); const [results, setResults] = useState([]); function handleChange(e) { const value = e.target.value; setQuery(value); // Heavy filtering (blocks input) const filtered = hugeList.filter(item => item.includes(value)); setResults(filtered); } return ( <> <input value={query} onChange={handleChange} /> <ul>{results.map(r => <li key={r}>{r}</li>)}</ul> </> ); } ``` The problem: on fast typing, React has to **re-render a huge list** for every character. The UI "freezes" - the cursor lags behind. --- ## The fix with `startTransition` ```javascript import { startTransition, useState } from 'react'; function Search() { const [query, setQuery] = useState(''); const [results, setResults] = useState([]); function handleChange(e) { const value = e.target.value; setQuery(value); // urgent update (text input) // deferred (low-priority) update startTransition(() => { const filtered = hugeList.filter(item => item.includes(value)); setResults(filtered); }); } return ( <> <input value={query} onChange={handleChange} /> <ul>{results.map(r => <li key={r}>{r}</li>)}</ul> </> ); } ``` What happens: 1. React sees that state updates are inside `startTransition()`; 2. It **queues them with low priority**; 3. It first renders the fast, important changes (`setQuery`); 4. Then, when "free", it does the "heavy" ones (`setResults`); 5. As a result, the interface stays responsive. --- ## Visually | Without `startTransition` | With `startTransition` | |---|---| | Input is blocked | Input is smooth | | Rendering a huge list stalls things | React defers rendering the list | | The UI feels "heavy" | The UI is responsive and alive | --- ## 1. How "priority" works in React 18 React now distinguishes two types of updates: | Type of update | Example | Priority | |---|---|---| | Urgent | Text input, clicks, scrolling | Run immediately | | Non-urgent (Transition) | Updating a list, filtering, loading data | Run when React is "free" | `startTransition()` marks updates as "non-urgent". React can **pause**, **cancel**, or **restart** them if new urgent updates arrive in the meantime. --- ## 2. With `useTransition()` - managing transition state React also provides the `useTransition()` hook - a convenient wrapper around `startTransition()` with a loading indicator: ```javascript import { useTransition, useState } from 'react'; function Search() { const [query, setQuery] = useState(''); const [results, setResults] = useState([]); const [isPending, startTransition] = useTransition(); function handleChange(e) { const value = e.target.value; setQuery(value); startTransition(() => { const filtered = hugeList.filter(item => item.includes(value)); setResults(filtered); }); } return ( <> <input value={query} onChange={handleChange} /> {isPending && <p>Updating results...</p>} <ul>{results.map(r => <li key={r}>{r}</li>)}</ul> </> ); } ``` `useTransition()` returns: - `isPending` - `true` while the transition is running (handy for showing a loader); - `startTransition()` - a function for running low-priority updates. --- ## 3. Asynchronous scenarios: API requests ```javascript import { useState, startTransition, Suspense } from "react"; import useSWR from "swr"; const fetcher = (url) => fetch(url).then(r => r.json()); function SearchResults({ query }) { const { data } = useSWR(`/api/search?q=${query}`, fetcher, { suspense: true }); return <ul>{data.results.map(r => <li key={r}>{r}</li>)}</ul>; } export function Search() { const [query, setQuery] = useState(''); const [displayQuery, setDisplayQuery] = useState(''); function handleChange(e) { const value = e.target.value; setQuery(value); // update the "visible" query with a delay startTransition(() => setDisplayQuery(value)); } return ( <> <input value={query} onChange={handleChange} placeholder="Search..." /> <Suspense fallback={<p>Loading...</p>}> <SearchResults query={displayQuery} /> </Suspense> </> ); } ``` On fast typing: - React updates the field instantly (`query`); - it defers changing `displayQuery` and making a new request; - the UI stays responsive even with large amounts of data. --- ## 4. Difference from `useDeferredValue()` | Hook / API | What it does | Example | |---|---|---| | `startTransition(fn)` | defers the *execution* of state updates | `startTransition(() => setList(...))` | | `useDeferredValue(value)` | defers the *use* of a value | `const deferred = useDeferredValue(value)` | Both solve the same problem - keeping the interface smooth - but they apply at different levels: - `startTransition()` - when you **set state**; - `useDeferredValue()` - when you **use state in a component**. --- ## 5. Where `startTransition()` is useful | Scenario | Benefit | |---|---| | Search across a large array | fast typing, filtering deferred | | Switching tabs | the old tab stays until the new one is ready | | Rendering large tables / lists | React doesn't freeze on updates | | Suspense + API | smooth asynchronous transitions | | Updating charts / filters | no lag or blocking the UI | --- ## Summary | What it does | Why it matters | |---|---| | Marks updates as "low priority" | React can defer them | | Keeps the UI responsive | fast actions (typing, clicking) run right away | | Enables smooth transitions | no "freezes" and "flicker" | | Works with `useTransition()` and `Suspense` | full control over async UX | | Foundation of Concurrent Rendering | React itself decides what to update first | --- ### In short: > `startTransition()` is a way to tell React: > "This update isn't urgent - do it whenever it's convenient." > > It makes the interface **instantly responsive**, > especially with heavy renders, filtering, and asynchronous loading.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.