Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке "startTransition()"?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`startTransition(callback)`** повідомляє React, що оновлення стану всередині `callback` можуть бути відкладені (мають низький пріоритет). **Ключове:** це спосіб сказати React "зроби це оновлення, але не поспішай, спочатку відрендери те, що важливе для UX (наприклад, введення тексту)".Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що таке `startTransition()` > `startTransition(callback)` - повідомляє React, > що оновлення стану всередині `callback` **можуть бути відкладені** (мають *низький пріоритет*). Простіше кажучи: > Це спосіб сказати React: > "Зроби це оновлення, але **не поспішай**, > спочатку відрендери те, що важливе для UX (наприклад, введення тексту)." --- ## Приклад без `startTransition` ```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 повинен **перерендерити величезний список** на кожен символ. UI "фризиться" - курсор рухається із затримкою. --- ## Рішення з `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); // термінове оновлення (введення тексту) // відкладене (низькопріоритетне) оновлення 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> </> ); } ``` Що відбувається: 1. React бачить, що всередині `startTransition()` знаходяться оновлення стану; 2. Він **ставить їх у чергу з низьким пріоритетом**; 3. Спочатку відмальовує швидкі, важливі зміни (`setQuery`); 4. Потім, коли "вільний", виконує "важкі" (`setResults`); 5. У результаті інтерфейс залишається відзивчивим. --- ## Візуально | Без `startTransition` | З `startTransition` | |---|---| | Введення блокується | Введення плавне | | Рендер величезного списку гальмує | React відкладає рендер списку | | UI здається "важким" | UI відзивчивий і живий | --- ## 1. Як працює "пріоритет" у React 18 React тепер розрізняє два типи оновлень: | Тип оновлення | Приклад | Пріоритет | |---|---|---| | Термінові (Urgent) | Введення тексту, кліки, скрол | Виконуються одразу | | Нетермінові (Transition) | Оновлення списку, фільтрація, завантаження даних | Виконуються, коли React "вільний" | `startTransition()` позначає оновлення як "нетермінові". React може їх **призупинити**, **скасувати** або **перезапустити**, якщо за цей час приходять нові термінові оновлення. --- ## 2. З `useTransition()` - керуємо станом переходу React також надає хук `useTransition()` - зручну обгортку для `startTransition()` з індикатором завантаження: ```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>Оновлення результатів...</p>} <ul>{results.map(r => <li key={r}>{r}</li>)}</ul> </> ); } ``` `useTransition()` повертає: - `isPending` - `true`, поки перехід виконується (зручно для показу loader); - `startTransition()` - функцію для запуску низькопріоритетних оновлень. --- ## 3. Асинхронні сценарії: запити до API ```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); // оновлюємо "видимий" запит відкладено 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: > "Це оновлення не термінове - можеш зробити його, коли буде зручно." > > Він робить інтерфейс **миттєво відзивчивим**, > особливо при важких рендерах, фільтрації та асинхронних завантаженнях.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.