Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке "Transition Updates"?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Transition Update** - це *низькопріоритетне* оновлення стану, яке React може **виконати пізніше**, **призупинити** чи **скасувати**, якщо саме зараз відбуваються важливіші (термінові) дії користувача. **Ключове:** Transitions - це оновлення, які можна відкласти, щоб не заважати швидкому відгуку UI.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що таке Transition Updates > **Transition Update** - це *низькопріоритетне* оновлення стану, > яке React може **виконати пізніше**, **призупинити** чи **скасувати**, > якщо саме зараз відбуваються важливіші (термінові) дії користувача. Простіше кажучи: > **Transitions = оновлення, які можна відкласти**, > щоб не заважати швидкому відгуку UI. --- ## 1. Проблема, яку вирішують Transitions До React 18 усі виклики `setState()` були **рівнозначні**: React виконував усі оновлення з однаковим пріоритетом. ### Приклад: Користувач друкує текст, і при кожному введенні фільтрується величезний список: ```javascript function Search() { const [query, setQuery] = useState(''); const [results, setResults] = useState([]); function handleChange(e) { const value = e.target.value; setQuery(value); setResults(filterBigList(value)); // важке оновлення } return ( <> <input value={query} onChange={handleChange} /> <ResultsList items={results} /> </> ); } ``` У React 17 UI може "лагати": поле вводу підвисає, поки React рендерить список. --- ## 2. Як вирішує це React 18 з Transition Updates Тепер можна позначити **частину оновлень** як *нетермінові* (transitions): ```javascript import { 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); // термінове оновлення (ввід) startTransition(() => { setResults(filterBigList(value)); // відкладене (важке) оновлення }); } return ( <> <input value={query} onChange={handleChange} /> {isPending && <Spinner />} {/* поки чекаємо */} <ResultsList items={results} /> </> ); } ``` Тепер: - поле вводу **оновлюється миттєво**; - React **відкладає** фільтрацію списку; - можна показати індикатор завантаження `isPending`, поки Transition не завершений. --- ## 3. Що робить `startTransition()` під капотом 1. React отримує функцію, передану в `startTransition()`; 2. позначає оновлення всередині як **низькопріоритетні**; 3. якщо в цей час приходять **термінові** оновлення (наприклад, натискання клавіш) - React **призупиняє Transition**, щоб інтерфейс не "завис"; 4. щойно потік звільняється - React **відновлює** виконання Transition. --- ## 4. "Термінові" vs "Перехідні" оновлення | Тип оновлення | Приклад | Пріоритет | Можна перервати? | Приклад API | |---|---|---|---|---| | **Urgent (термінові)** | Набір тексту, кліки, фокус, навігація | Високий | Ні | `setState()` напряму | | **Transition (відкладені)** | Фільтрація, сортування, підвантаження даних | Низький | Так | `startTransition()` / `useTransition()` | React тепер **розуміє різницю між UX-важливим** і **ресурсно-важким** оновленням. --- ## 5. Як React вирішує, що рендерити першим - React працює з **двома чергами оновлень**: - терміновими (input, focus, scroll тощо); - відкладеними (transitions). - Якщо користувач вводить текст - термінові оновлення проходять **негайно**. - Усі transitions React може: - **відкласти** до наступного кадру; - **призупинити**, якщо користувач продовжує ввід; - **скасувати**, якщо прийшли нові дані; - **виконати заново**, коли користувач зупинився. --- ## 6. Приклад з індикатором `isPending` `useTransition()` повертає: - `isPending` - прапорець, що вказує, що Transition зараз виконується; - `startTransition(callback)` - функцію для запуску низькопріоритетних оновлень. ```javascript const [isPending, startTransition] = useTransition(); startTransition(() => { setSearchResults(fetchFilteredResults(query)); }); ``` Коли React призупиняє рендер, `isPending = true` - можна показати спінер, скелетон чи напис "Завантаження…". --- ## 7. React сам керує Transitions Transitions працюють **лише при активному Concurrent Rendering**, тобто коли корінь застосунку створений через: ```javascript import { createRoot } from 'react-dom/client'; const root = createRoot(document.getElementById('root')); root.render(<App />); ``` Якщо ти використовуєш старий `ReactDOM.render()`, `startTransition` просто не дасть ефекту - React не зможе призупиняти рендер. --- ## 8. Приклад з асинхронними діями ```javascript function Products() { const [filter, setFilter] = useState('all'); const [data, setData] = useState([]); const [isPending, startTransition] = useTransition(); const handleFilter = (newFilter) => { startTransition(async () => { const res = await fetch(`/api/products?filter=${newFilter}`); const data = await res.json(); setData(data); setFilter(newFilter); }); }; return ( <> <Filters onChange={handleFilter} /> {isPending && <Skeleton />} <ProductList items={data} /> </> ); } ``` UI залишається відповідним, навіть якщо запит до API займає час. --- ## 9. Нове в React 19 React 19 покращив Transitions - тепер `startTransition()` може бути **асинхронним**: ```javascript await startTransition(async () => { await someAsyncOperation(); }); ``` Більше не потрібно вручну керувати станом очікування - React сам розуміє, коли Transition завершений. --- ## Підсумок > **Transition Updates** - це оновлення стану, > які React виконує *плавно*, *асинхронно* і *без лагів інтерфейсу*, > відкладаючи їх, поки користувач взаємодіє з UI. --- ### Коротке порівняння | Характеристика | Звичайний `setState` | Transition Update | |---|---|---| | Пріоритет | Високий | Низький | | Можна перервати | Ні | Так | | Затримка в UI | Можлива (лаг) | Немає | | Основне застосування | Події UI (ввід, клік) | Довгі обчислення, фільтри, завантаження | | API | `setState()` | `useTransition()` / `startTransition()` |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.