Skip to main content

Що робить "flushSync()"?

Визначення

flushSync(callback) - це функція з пакету react-dom, яка змушує React негайно "скинути" (flush) всі очікувані оновлення стану всередині переданого колбека і синхронно оновити DOM.

javascript
import { flushSync } from 'react-dom'; flushSync(() => { setState(newValue); });

Після виходу з flushSync() React гарантує, що:

  • компонент уже перерендерений;
  • DOM оновлений;
  • усі layout-ефекти (useLayoutEffect) для цього оновлення вже відпрацювали.

1. Навіщо він взагалі потрібен

Типово React працює асинхронно - особливо в React 18 з Concurrent Rendering. Він може:

  • відкладати оновлення;
  • об'єднувати декілька setState в один рендер (batching);
  • не одразу оновлювати DOM.

Іноді це створює ситуації, коли тобі потрібно негайно побачити результат у DOM, наприклад:

  • щоб виміряти елемент (offsetHeight);
  • щоб плавно запустити анімацію;
  • щоб зробити фокус;
  • щоб синхронно відреагувати на дію користувача.

2. Приклад: без flushSync

javascript
function Example() { const [count, setCount] = useState(0); const divRef = useRef(); const handleClick = () => { setCount(c => c + 1); console.log(divRef.current.textContent); // старе значення }; return <div ref={divRef}>{count}</div>; }

Що відбувається:

  • setCount ставить оновлення в чергу;
  • React планує рендер, але не виконує його миттєво;
  • лог виконується до оновлення DOM -> ти бачиш старе значення.

3. Приклад з flushSync

javascript
import { flushSync } from 'react-dom'; function Example() { const [count, setCount] = useState(0); const divRef = useRef(); const handleClick = () => { flushSync(() => { setCount(c => c + 1); // оновлення стану }); console.log(divRef.current.textContent); // вже нове значення }; return <div ref={divRef}>{count}</div>; }

Тепер React:

  1. Одразу виконує setCount();
  2. Синхронно викликає рендер і commit;
  3. Оновлює DOM;
  4. Тільки потім виходить із flushSync;
  5. Лог покаже актуальний count.

4. Як це працює під капотом

flushSync:

  • тимчасово вимикає concurrent batching;
  • змушує React виконати всі очікувані оновлення (включно з тими, що були заплановані раніше);
  • негайно викликає commit phase, оновлюючи DOM і layout-ефекти;
  • потім повертає React назад у звичайний асинхронний режим.
javascript
Без flushSync: setState() → чекаємо → React вирішує коли оновити З flushSync: setState() → одразу render → commit → готовий DOM

5. Де це потрібно застосовувати

СценарійЧому потрібен flushSync
Потрібно виміряти DOM після setStateЩоб отримати актуальні розміри
Запуск анімації одразу після зміниDOM повинен бути оновлений миттєво
Фокусування або скрол після оновленняЩоб елемент точно існував у DOM
Робота із зовнішніми бібліотеками (GSAP, D3, Chart.js)Ці бібліотеки очікують актуальний стан DOM
Іноді - при інтеграції з React Transition Group, Portal або Drag'n'DropКоли commit повинен відбутися синхронно

6. Але використовувати обережно!

React спеціально робить рендер асинхронним, щоб:

  • не блокувати інтерфейс,
  • оптимізувати батчинг оновлень,
  • підвищувати чутливість UI.

flushSync() вимикає ці переваги для конкретної ділянки коду.

Не роби так:

javascript
flushSync(() => { setA(1); }); flushSync(() => { setB(2); });

Кожен виклик змусить React рендерити і комітити заново, що б'є по продуктивності. Краще згрупувати декілька оновлень в один flushSync().


7. Взаємодія з життєвим циклом

ЕтапЩо відбувається при flushSync()
Render PhaseЗапускається негайно для всіх змінених компонентів
Commit PhaseВідбувається синхронно
Ефекти (useLayoutEffect)Виконуються одразу після commit
Ефекти (useEffect)Все ще виконуються асинхронно (на наступному tick)

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

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

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