Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як React 18 змінив роботу життєвого циклу?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)Головна ідея React 18 - **Concurrent Rendering**: рендер став асинхронним і перериваним (через Fiber concurrent mode), і React тепер може призупиняти рендер, відкочувати незавершені зміни, повторно викликати ефекти і об'єднувати декілька state-оновлень в одну "сесію". **Ключове:** у продакшн-режимі ефекти все ще викликаються один раз - "двічі" вони спрацьовують тільки в dev-режимі (Strict Mode), щоб перевірити, що ефекти й cleanup детерміновані.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## 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 Phase** | React обчислює, що потрібно оновити (може бути призупинена) | `render()`, `useMemo`, `useCallback`, `shouldComponentUpdate` | | **Commit Phase** | React застосовує зміни до 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 Batching** | React тепер групує всі state-оновлення, навіть у промісах | Менше "зайвих" ререндерів, інша поведінка `useEffect` | | **Transitions (**`startTransition`**)** | Дозволяє розділяти "термінові" і "нетермінові" оновлення | Життєвий цикл низькопріоритетних оновлень може викликатися пізніше | | **useId, useSyncExternalStore, useInsertionEffect** | Нові хуки для коректної роботи в concurrent режимі | Оптимізують доступ до DOM, стилів і зовнішніх даних | --- ## 6. Що змінилося для `useEffect` | Поведінка | React 17 | React 18 | |---|---|---| | Ефект викликається один раз у dev | Так | Ні - двічі (Strict Mode) | | Очищення викликається тільки при демонтуванні | Так | Ні - також перед повторним ефектом | | Ефект може бути відкладений (deferred) | Ні | Так (через concurrent rendering) | | Можливий "скасований" ефект (якщо commit не відбувся) | Ні | Так | --- ## 7. Головне, що потрібно пам'ятати - React 18 не "ламає" життєвий цикл, а робить його **більш точним, асинхронним і безпечним**. - У продакшні ефекти все ще викликаються **один раз** - "двічі" тільки в dev. - Важливо писати **чисті ефекти** - без побічних дій у тілі компонента і без залежності від кількості викликів. --- ## Коротка зведена таблиця | Що змінилося | React < 18 | React 18 | |---|---|---| | Рендерінг | Синхронний | Асинхронний / пріоритетний | | Життєвий цикл | Однопрохідний | Може бути призупинений / повторений | | Ефекти (`useEffect`) | Один виклик | Подвійний виклик у StrictMode (dev) | | Очищення (`cleanup`) | Тільки при unmount | Також при повторному монтуванні | | Старі методи (`componentWill*`) | Працюють (legacy mode) | Несумісні | | State batching | Тільки всередині подій | Автоматично всюди | | Нові хуки | - | `useId`, `useSyncExternalStore`, `useInsertionEffect` |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.