Що таке "startTransition()"?
Що таке startTransition()
startTransition(callback)- повідомляє React, що оновлення стану всерединіcallbackможуть бути відкладені (мають низький пріоритет).
Простіше кажучи:
Це спосіб сказати React: "Зроби це оновлення, але не поспішай, спочатку відрендери те, що важливе для UX (наприклад, введення тексту)."
Приклад без startTransition
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 повинен перерендерити величезний список на кожен символ. UI "фризиться" - курсор рухається із затримкою.
Рішення з startTransition
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); // термінове оновлення (введення тексту)
// відкладене (низькопріоритетне) оновлення
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>
</>
);
}Що відбувається:
- React бачить, що всередині
startTransition()знаходяться оновлення стану; - Він ставить їх у чергу з низьким пріоритетом;
- Спочатку відмальовує швидкі, важливі зміни (
setQuery); - Потім, коли "вільний", виконує "важкі" (
setResults); - У результаті інтерфейс залишається відзивчивим.
Візуально
Без startTransition | З startTransition |
|---|---|
| Введення блокується | Введення плавне |
| Рендер величезного списку гальмує | React відкладає рендер списку |
| UI здається "важким" | UI відзивчивий і живий |
1. Як працює "пріоритет" у React 18
React тепер розрізняє два типи оновлень:
| Тип оновлення | Приклад | Пріоритет |
|---|---|---|
| Термінові (Urgent) | Введення тексту, кліки, скрол | Виконуються одразу |
| Нетермінові (Transition) | Оновлення списку, фільтрація, завантаження даних | Виконуються, коли React "вільний" |
startTransition() позначає оновлення як "нетермінові".
React може їх призупинити, скасувати або перезапустити,
якщо за цей час приходять нові термінові оновлення.
2. З useTransition() - керуємо станом переходу
React також надає хук useTransition() -
зручну обгортку для startTransition() з індикатором завантаження:
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>Оновлення результатів...</p>}
<ul>{results.map(r => <li key={r}>{r}</li>)}</ul>
</>
);
}useTransition() повертає:
isPending-true, поки перехід виконується (зручно для показу loader);startTransition()- функцію для запуску низькопріоритетних оновлень.
3. Асинхронні сценарії: запити до API
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);
// оновлюємо "видимий" запит відкладено
startTransition(() => setDisplayQuery(value));
}
return (
<>
<input value={query} onChange={handleChange} placeholder="Пошук..." />
<Suspense fallback={<p>Завантаження...</p>}>
<SearchResults query={displayQuery} />
</Suspense>
</>
);
}При швидкому введенні:
- React оновлює поле миттєво (
query); - відкладено змінює
displayQueryі робить новий запит; - UI залишається відзивчивим, навіть при великій кількості даних.
4. Відмінність від useDeferredValue()
| Хук / API | Що робить | Приклад |
|---|---|---|
startTransition(fn) | відкладає виконання оновлень стану | startTransition(() => setList(...)) |
useDeferredValue(value) | відкладає використання значення | const deferred = useDeferredValue(value) |
Обидва вирішують одну задачу - зробити інтерфейс плавним, але застосовуються на різних рівнях:
startTransition()- коли встановлюєш стан;useDeferredValue()- коли використовуєш стан у компоненті.
5. Де startTransition() корисний
| Сценарій | Перевага |
|---|---|
| Пошук по великому масиву | швидке введення, фільтрація відкладена |
| Перемикання вкладок | стара вкладка залишається, поки нова не готова |
| Рендер великих таблиць / списків | React не фризиться при оновленнях |
| Suspense + API | плавні асинхронні переходи |
| Оновлення графіків / фільтрів | без лагів і блокування UI |
Підсумок
| Що робить | Чому важливо |
|---|---|
| Позначає оновлення як "низькопріоритетні" | React може їх відкласти |
| Зберігає відзивчивість UI | швидкі дії (введення, клік) виконуються одразу |
| Дозволяє плавні переходи | без "фризів" і "мигання" |
Працює з useTransition() і Suspense | повний контроль за async UX |
| Основа Concurrent Rendering | React сам вирішує, що оновити першим |
Коротко:
startTransition()- це спосіб сказати React: "Це оновлення не термінове - можеш зробити його, коли буде зручно."Він робить інтерфейс миттєво відзивчивим, особливо при важких рендерах, фільтрації та асинхронних завантаженнях.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.