Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «setState у React 18». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)У React 18 **`setState()`** став асинхронним і конкурентним: React може ставити оновлення в чергу, керувати їхнім пріоритетом і батчити їх у будь-якому контексті (не тільки в React-подіях). **Ключове:** automatic batching тепер працює всюди - у `setTimeout`, `Promise`, `async/await` і навіть у кастомних хуках, тож кілька викликів `setState` призводять до одного рендеру.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## 1. Головна зміна - асинхронність і "розумний" контроль пріоритетів До React 18 усі оновлення `setState()` були **синхронними в межах одного рендеру**. React одразу запускав перерендер, щойно ти викликав `setState()` (з можливим batching усередині події). Тепер - у **React 18+ (Concurrent Mode)**: > `setState()` може виконуватись **асинхронно і конкурентно** - React **може відкласти, призупинити, об'єднати або скасувати** рендер, якщо в цей момент відбуваються інші (більш пріоритетні) оновлення. ### Простіше кажучи: React тепер вирішує: - "Це термінове оновлення? Тоді робимо одразу." - "А це не термінове (наприклад, фільтрація списку)? Тоді відкладемо, поки користувач друкує." --- ## 2. Automatic Batching тепер працює **всюди** Раніше batching (об'єднання кількох `setState()` в один рендер) працював тільки в подіях React (`onClick`, `onChange` тощо). Тепер - **у будь-яких контекстах**: `setTimeout`, `Promise`, `async/await`, `fetch` і навіть усередині кастомних хуків. ```javascript setTimeout(() => { setCount(c => c + 1); setFlag(f => !f); }, 1000); // React 18: один спільний рендер // React 17: два окремих рендери ``` Тобто: React тепер **автоматично групує** всі оновлення стану в межах однієї "ітерації" подієвого циклу. --- ## 3. setState() тепер може бути "відкладеним" (deferred) React 18 додав API `startTransition()` і хук `useTransition()`, які дозволяють явно позначити оновлення як **"низькопріоритетні"**. ```javascript const [isPending, startTransition] = useTransition(); function handleChange(e) { const value = e.target.value; startTransition(() => { setFilter(value); // React виконає пізніше, щоб не блокувати введення }); } ``` Тут: - оновлення фільтра (низький пріоритет) виконується "у фоні"; - користувацьке введення (високий пріоритет) обробляється миттєво. Раніше React **не вмів розділяти пріоритети оновлень**, тепер - вміє. --- ## 4. React може **перервати або скасувати** проміжний рендер Якщо під час рендеру надходить новий стан, React може: - скасувати вже розпочатий рендер (якщо він ще не завершений); - почати новий із більш актуальними даними. Це стало можливим завдяки **Concurrent Rendering**. У старому React 17 процес рендеру був блокуючим - React повинен був "дійти до кінця". --- ## 5. Черговість (order) і передбачуваність Механізм "черг оновлень" (`setState` queue) тепер став **гнучкішим**: | Сценарій | React 17 | React 18 | |---|---|---| | Кілька `setState` підряд | Виконувалися синхронно в одному рендері (усередині події) | Все ще об'єднуються, але порядок гарантується навіть при асинхронних викликах | | Оновлення в промісах | Кожен `setState` викликав окремий рендер | Усі об'єднуються в один спільний рендер | | Оновлення всередині `startTransition` | Не існувало | Оновлення виконуються пізніше, з низьким пріоритетом | --- ## 6. Приклад порівняння ### React 17 (застаріла поведінка) ```javascript setTimeout(() => { setCount(c => c + 1); setFlag(f => !f); }, 1000); // Виконає 2 рендери (кожен setState по черзі) ``` ### React 18 (нова поведінка) ```javascript setTimeout(() => { setCount(c => c + 1); setFlag(f => !f); }, 1000); // Виконає 1 рендер (automatic batching) ``` --- ## 7. Примусове оновлення (flushSync) Якщо потрібно **одразу оновити DOM**, оминаючи batching, можна використати `flushSync()`: ```javascript import { flushSync } from 'react-dom'; flushSync(() => { setCount(c => c + 1); }); // React негайно перерендерить компонент ``` Це корисно, коли потрібно, щоб оновлення з'явилося *до* наступного кадру (наприклад, для точних вимірювань layout). --- ## 8. Поведінка в Strict Mode (у Dev-режимі) У React 18 Strict Mode **монтує і розмонтовує компоненти двічі**, щоб виявити побічні ефекти, пов'язані з асинхронними `setState`. Якщо ти бачиш, що `setState` викликається двічі - це **не баг**, а механізм перевірки коректності побічних ефектів. --- ## Підсумок > У React 18 `setState()` став: > > - **асинхронним і конкурентним** - React може ставити оновлення в чергу і керувати їхнім пріоритетом; > - **автоматично батчиться** в будь-яких контекстах; > - **переривним** - можна скасувати проміжний рендер, якщо надійшов новий стан; > - **продуктивнішим** і **плавнішим для UX**.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.