Skip to main content

Що робить useTransition()?

Що робить useTransition()

useTransition() дозволяє позначити частину оновлень стану як "перехід" (transition) - тобто менш пріоритетне оновлення, яке React може відкласти заради важливіших (наприклад, вводу тексту, кліків, анімацій).

Простіше кажучи:

Це спосіб сказати React: "Це оновлення не термінове - можеш зробити його трохи пізніше, коли закінчиш зі швидкими справами."


Приклад без useTransition

javascript
function Search() { const [query, setQuery] = useState(''); const [results, setResults] = useState([]); function handleChange(e) { const value = e.target.value; setQuery(value); // Емулюємо важку фільтрацію 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> </> ); }

Проблема: при швидкому введенні React перемальовує величезний список на кожному символі, через що input "лагає" - курсор підвисає, а оновлення гальмують.


1. Рішення з useTransition

javascript
import { useState, useTransition } 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); // оновлюємо input одразу (високий пріоритет) startTransition(() => { // оновлюємо результати пізніше (низький пріоритет) const filtered = hugeList.filter(item => item.includes(value)); setResults(filtered); }); } return ( <> <input value={query} onChange={handleChange} /> {isPending && <p>Завантаження...</p>} <ul>{results.map(r => <li key={r}>{r}</li>)}</ul> </> ); }

Що робить React:

  1. setQuery() виконується одразу → поле вводу залишається відповідним;
  2. React відкладає setResults() - це "transition update";
  3. Поки перехід виконується → isPending = true (можна показати loader);
  4. Коли React завершить перехід - isPending скидається.

UI залишається плавним, ввід миттєвий, список оновлюється трохи пізніше, але без лагів.


Що відбувається "під капотом"

React тепер має два пріоритети оновлень:

Тип оновленняПрикладПріоритет
Термінове (Urgent)Ввід тексту, кліки, скролВиконується одразу
Відкладене (Transition)Фільтрація, підвантаження даних, перемикання вкладокМожна призупинити

Коли ти викликаєш startTransition(fn):

  • React ставить оновлення всередині fn у чергу з низьким пріоритетом;
  • спочатку обробляє термінові оновлення (наприклад, рендер input);
  • потім, коли "вільний", запускає перехід;
  • якщо під час переходу користувач щось робить → React може перервати перехід і почати заново (без фризів).

2. Асинхронні сценарії: запити до API

javascript
import { useState, useTransition, 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(''); const [isPending, startTransition] = useTransition(); function handleChange(e) { const value = e.target.value; setQuery(value); startTransition(() => setDisplayQuery(value)); // асинхронний перехід } return ( <> <input value={query} onChange={handleChange} /> {isPending && <p>Завантаження...</p>} <Suspense fallback={<p>Завантаження результатів...</p>}> <SearchResults query={displayQuery} /> </Suspense> </> ); }

Що робить код:

  • користувач швидко друкує → React миттєво оновлює input;
  • displayQuery оновлюється "відкладено" → SWR запускає fetch;
  • поки дані не прийшли → React показує fallback з Suspense;
  • усе плавно, без блокування інтерфейсу.

3. Значення, що повертає useTransition()

javascript
const [isPending, startTransition] = useTransition();
ЗміннаОпис
isPendingtrue, поки виконується перехід (можна показати loader / вимкнути кнопку)
startTransition(cb)запускає функцію як "відкладене" оновлення стану

4. Відмінність від useDeferredValue()

ХукЩо робитьКоли використовувати
useTransition()відкладає виконання оновлення стануколи ти встановлюєш стан (setState)
useDeferredValue()відкладає використання значенняколи ти передаєш значення у важкий компонент

Приклад:

javascript
// useTransition startTransition(() => setQuery(value)); // відкладено оновлюємо стан // useDeferredValue const deferredQuery = useDeferredValue(query); // відкладено використовуємо значення

5. Реальні кейси

СценарійЯк допомагає
Пошук по великому спискумиттєвий ввід, фільтрація відкладена
Переходи між вкладкамистара вкладка залишається, поки нова не готова
Оновлення таблиць / графіківплавний UI при фільтрації
Перехід на іншу сторінку (SPA)React показує "стару" сторінку до завантаження нової
Suspense + APIфонове підвантаження даних без блокування

6. Що відбувається візуально

Без useTransitionЗ useTransition
UI зависає при вводіUI відповідний
Новий контент замінює старий миттєво (блимає)Старий контент залишається, поки новий не готовий
Перехід здається "жорстким"Перехід плавний і природний

ПІДСУМОК

Що робитьЧому важливо
Відкладає "важкі" оновленняUI залишається відповідним
Розділяє пріоритетиReact не блокує ввід і кліки
Повертає isPendingможна показати індикатор
Працює з Suspenseплавні async-переходи
Спрощує UX при великих данихфільтри, пошук, сортування

Коротко:

useTransition() - це спосіб сказати React: "Ці оновлення не термінові - зроби їх, коли звільнишся."

Він робить UI миттєво відповідним, навіть якщо під капотом іде асинхронне підвантаження даних або важкий рендер.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.