Skip to main content

createRoot() vs render()

1. Основна різниця

ФункціяReactDOM.render() (до React 17)createRoot() (React 18+)
Тип рендерінгуСинхронний (legacy) - React блокує потік JS, поки не закінчить рендерКонкурентний (concurrent) - React може призупиняти, відновлювати і впорядковувати рендери за пріоритетами
Реакція на оновленняВсі оновлення виконуються послідовно, без пріоритетівОновлення діляться на термінові / нетермінові (через startTransition, useDeferredValue та ін.)
Automatic batching (групування setState)Працює тільки всередині React-подійПрацює всюди - навіть у setTimeout, промісах і async-функціях
Підтримка нових фіч React 18+Ні (не можна використовувати concurrent-можливості)Так (включає все: concurrent rendering, Suspense SSR, streaming тощо)
API для SSRReactDOM.hydrate()ReactDOM.hydrateRoot()
Керування оновленнями (flush, transitions)Немає контролюЄ хуки useTransition, startTransition, flushSync

2. Приклад до і після React 18

До (React 17)

javascript
import ReactDOM from "react-dom"; import App from "./App"; ReactDOM.render(<App />, document.getElementById("root"));

Цей виклик використовує старий синхронний механізм. Якщо в застосунку виконується важкий рендер, React не може перервати його, і інтерфейс може "зависнути".


Після (React 18+)

javascript
import { createRoot } from "react-dom/client"; import App from "./App"; const container = document.getElementById("root"); const root = createRoot(container); // новий "корінь" root.render(<App />);

Такий спосіб створює Concurrent Root. Тепер React може:

  • призупиняти рендер;
  • відкладати "низькопріоритетні" оновлення;
  • виконувати automatic batching;
  • працювати з startTransition() і useDeferredValue().

3. Поведінка при оновленні стану

Приклад з асинхронним кодом:

React 17 (старий render)

javascript
setTimeout(() => { setCount(c => c + 1); setFlag(f => !f); // буде 2 окремих рендери }, 1000);

React 18 (createRoot)

javascript
setTimeout(() => { setCount(c => c + 1); setFlag(f => !f); // один спільний рендер завдяки Automatic Batching }, 1000);

React тепер сам об'єднує оновлення навіть поза подіями React (наприклад, у промісах або таймерах).


4. Вплив на хуки і нові можливості

createRoot() включає підтримку нових React 18 API:

  • useTransition() / startTransition() - контроль пріоритету оновлень
  • useDeferredValue() - відкладені значення
  • useId() - стабільні ID між клієнтом і сервером
  • Suspense для data fetching і SSR (streaming, renderToPipeableStream)

Якщо ти використовуєш ReactDOM.render(), ці фічі не працюють - React залишається в "Legacy Mode".


5. Сумісність і міграція

  • Старий ReactDOM.render() все ще працює, але позначений як застарілий (deprecated).

  • Міграція максимально проста - просто замінити один виклик:

    javascript
    - ReactDOM.render(<App />, root); + const root = createRoot(root); + root.render(<App />);
  • Решту коду (компоненти, хуки, контекст тощо) міняти не потрібно.


Підсумкове порівняння в одній фразі

ReactDOM.render() - старий синхронний рендер без пріоритетів.

createRoot() - новий конкурентний рендер, що включає можливості React 18: batching, transitions, streaming SSR і плавний UI.

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

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

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