Що робить useTransition()?
Що робить useTransition()
useTransition()дозволяє позначити частину оновлень стану як "перехід" (transition) - тобто менш пріоритетне оновлення, яке React може відкласти заради важливіших (наприклад, вводу тексту, кліків, анімацій).
Простіше кажучи:
Це спосіб сказати React: "Це оновлення не термінове - можеш зробити його трохи пізніше, коли закінчиш зі швидкими справами."
Приклад без useTransition
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
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:
setQuery()виконується одразу → поле вводу залишається відповідним;- React відкладає
setResults()- це "transition update"; - Поки перехід виконується →
isPending = true(можна показати loader); - Коли React завершить перехід -
isPendingскидається.
UI залишається плавним, ввід миттєвий, список оновлюється трохи пізніше, але без лагів.
Що відбувається "під капотом"
React тепер має два пріоритети оновлень:
| Тип оновлення | Приклад | Пріоритет |
|---|---|---|
| Термінове (Urgent) | Ввід тексту, кліки, скрол | Виконується одразу |
| Відкладене (Transition) | Фільтрація, підвантаження даних, перемикання вкладок | Можна призупинити |
Коли ти викликаєш startTransition(fn):
- React ставить оновлення всередині
fnу чергу з низьким пріоритетом; - спочатку обробляє термінові оновлення (наприклад, рендер input);
- потім, коли "вільний", запускає перехід;
- якщо під час переходу користувач щось робить → React може перервати перехід і почати заново (без фризів).
2. Асинхронні сценарії: запити до API
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()
const [isPending, startTransition] = useTransition();| Змінна | Опис |
|---|---|
isPending | true, поки виконується перехід (можна показати loader / вимкнути кнопку) |
startTransition(cb) | запускає функцію як "відкладене" оновлення стану |
4. Відмінність від useDeferredValue()
| Хук | Що робить | Коли використовувати |
|---|---|---|
useTransition() | відкладає виконання оновлення стану | коли ти встановлюєш стан (setState) |
useDeferredValue() | відкладає використання значення | коли ти передаєш значення у важкий компонент |
Приклад:
// 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 миттєво відповідним, навіть якщо під капотом іде асинхронне підвантаження даних або важкий рендер.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.