Skip to main content

setState у React 18

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 17React 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.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.