Skip to main content

Як React 18 змінив роботу життєвого циклу?

1. Головна ідея React 18 - Concurrent Rendering

До React 18:

  • React рендерив компонент синхронно: якщо рендер почався, він ішов до кінця - не можна було призупинити, скасувати або об'єднати декілька оновлень.
  • Всі життєві цикли викликалися в чітко передбачуваному порядку (монтування -> commit -> ефекти).

З React 18:

  • Рендер став асинхронним і перериваним (через Fiber concurrent mode).
  • React тепер може:
    • призупиняти рендер,
    • відкочувати незавершені зміни,
    • повторно викликати ефекти,
    • об'єднувати декілька state-оновлень в одну "сесію".

Це напряму впливає на виклики життєвого циклу і хуків, оскільки тепер ефекти можуть виконуватися більше одного разу в dev-режимі, а "монтування" може бути симульоване декілька разів.


2. Поведінка в Strict Mode (React 18)

Найпомітніша для розробників зміна:

React 18 тепер викликає useEffect, useLayoutEffect, componentDidMount, componentWillUnmount - двічі (у DEV-режимі), щоб допомогти знайти "нечисті ефекти".

Це називається "Strict Mode double invocation" і відбувається тільки в dev, щоб перевірити, що твої ефекти і очищення (cleanup) детерміновані і не залежать від порядку виклику.

Приклад:

javascript
useEffect(() => { console.log('ефект'); return () => console.log('очищення'); }, []);

У React 18 (у StrictMode) ти побачиш:

javascript
ефект очищення ефект

Чому: React симулює демонтування і повторне монтування, щоб перевірити, що твій ефект коректно очищає за собою ресурси (таймери, слухачі, підписки).

Це не баг - це частина нової "concurrent safety check".


3. Зміна фаз життєвого циклу під капотом

Життєвий цикл тепер сприймається в рамках двох фаз Fiber:

ФазаПризначенняМетоди/хуки
Render PhaseReact обчислює, що потрібно оновити (може бути призупинена)render(), useMemo, useCallback, shouldComponentUpdate
Commit PhaseReact застосовує зміни до DOM (завжди синхронна)componentDidMount, componentDidUpdate, useLayoutEffect, useEffect

У React 18 Render Phase може:

  • запускатися багаторазово (React може "підготувати" різні версії UI і потім вибрати одну);
  • не доводитися до commit, якщо рендер скасований;
  • виконуватися у фоні (background rendering).

4. Що конкретно змінилося в поведінці життєвих циклів

componentWillMount, componentWillUpdate, componentWillReceiveProps

Офіційно застаріли ще раніше (React 16) і повністю несумісні з concurrent mode - React 18 їх взагалі не викликає в concurrent рендері. Замість них - безпечні аналоги:

  • getDerivedStateFromProps
  • getSnapshotBeforeUpdate
  • componentDidUpdate

componentDidMount / useEffect / useLayoutEffect

  • Все ще викликаються в commit phase, але React може викликати cleanup -> повторний ефект при переході між рендерами з різним пріоритетом.
  • У dev-режимі (StrictMode) виконуються двічі при монтуванні (див. вище).
  • У concurrent режимі React може скасувати рендер до commit, і тоді ефекти взагалі не будуть викликані (бо DOM не змінився).

componentDidUpdate

  • Викликається тільки для тих компонентів, які реально зафіксовані (committed). Якщо рендер скасований (наприклад, при переході на новий стан) - метод не викликається.

componentWillUnmount / cleanup у useEffect

  • Тепер React гарантовано викликає cleanup:
    • при демонтуванні,
    • перед новим ефектом,
    • при скасованому рендері (у деяких випадках у dev-режимі).
  • Це робить логіку ефектів більш передбачуваною і безпечною.

shouldComponentUpdate

  • Поведінка не змінилася напряму, але React тепер може перервати або відкласти рендер, тому перевірка може відбуватися декілька разів перед коммітом.

5. Нові можливості React 18, що впливають на "життєвий цикл"

Нова фічаЩо робитьЯк впливає
Concurrent RenderingАсинхронний, пріоритетний рендерінгМетоди можуть викликатися не один раз, ефекти можуть відкладатися
Automatic BatchingReact тепер групує всі state-оновлення, навіть у промісахМенше "зайвих" ререндерів, інша поведінка useEffect
Transitions (startTransition)Дозволяє розділяти "термінові" і "нетермінові" оновленняЖиттєвий цикл низькопріоритетних оновлень може викликатися пізніше
useId, useSyncExternalStore, useInsertionEffectНові хуки для коректної роботи в concurrent режиміОптимізують доступ до DOM, стилів і зовнішніх даних

6. Що змінилося для useEffect

ПоведінкаReact 17React 18
Ефект викликається один раз у devТакНі - двічі (Strict Mode)
Очищення викликається тільки при демонтуванніТакНі - також перед повторним ефектом
Ефект може бути відкладений (deferred)НіТак (через concurrent rendering)
Можливий "скасований" ефект (якщо commit не відбувся)НіТак

7. Головне, що потрібно пам'ятати

  • React 18 не "ламає" життєвий цикл, а робить його більш точним, асинхронним і безпечним.
  • У продакшні ефекти все ще викликаються один раз - "двічі" тільки в dev.
  • Важливо писати чисті ефекти - без побічних дій у тілі компонента і без залежності від кількості викликів.

Коротка зведена таблиця

Що змінилосяReact < 18React 18
РендерінгСинхроннийАсинхронний / пріоритетний
Життєвий циклОднопрохіднийМоже бути призупинений / повторений
Ефекти (useEffect)Один викликПодвійний виклик у StrictMode (dev)
Очищення (cleanup)Тільки при unmountТакож при повторному монтуванні
Старі методи (componentWill*)Працюють (legacy mode)Несумісні
State batchingТільки всередині подійАвтоматично всюди
Нові хуки-useId, useSyncExternalStore, useInsertionEffect

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

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

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