Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «ErrorBoundary і Suspense». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)Так, `ErrorBoundary` і `Suspense` чудово працюють разом: React обробляє і `Promise`, і `Error` однаково - через "викидання" (throw), тільки `Promise` веде до fallback від `Suspense` (очікування), а `Error` - до fallback від `ErrorBoundary` (помилка). **Ключове:** рекомендований порядок вкладеності - `<ErrorBoundary><Suspense><Component /></Suspense></ErrorBoundary>`, щоб ErrorBoundary ловив будь-які помилки всередині Suspense-зони.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Різниця між Suspense і Error Boundary | Компонент | Що робить | Коли спрацьовує | |---|---|---| | `<Suspense>` | Показує **fallback**, поки компонент **ще не готовий** (наприклад, іде завантаження даних або коду). | Коли компонент "призупиняється" (throws a *Promise*). | | `<ErrorBoundary>` | Показує **fallback при помилці**, коли компонент **впав**. | Коли компонент "впав" (throws an *Error*). | > React обробляє і `Promise`, і `Error` однаково - через "викидання" (throw). > Різниця в тому, *що саме було викинуто*: > - `Promise` -> чекаємо (Suspense) > - `Error` -> показуємо помилку (ErrorBoundary) --- ## Як вони працюють разом React йде згори вниз: 1. Компонент може **"призупинити"** рендер (кинути `Promise`) -> React шукає найближчий `<Suspense>`. 2. Якщо компонент **"впав"** (кинув `Error`) -> React шукає найближчий `<ErrorBoundary>`. Тому їх можна і потрібно **вкладати** одне в одне, щоб різні ситуації (завантаження і помилка) оброблялися коректно. --- ## Приклад правильного поєднання ```javascript import { Suspense } from "react"; import ErrorBoundary from "./ErrorBoundary"; import { UserProfile } from "./UserProfile"; function App() { return ( <ErrorBoundary fallback={<h2>Error loading data</h2>}> <Suspense fallback={<h2>Loading profile...</h2>}> <UserProfile /> </Suspense> </ErrorBoundary> ); } ``` Що станеться: - якщо `UserProfile` *ще не завантажився* (наприклад, `React.lazy()` або Suspense-запит) -> покажеться **fallback з** `Suspense` ("Loading..."); - якщо в `UserProfile` станеться *помилка* (наприклад, `throw new Error()`) -> покажеться **fallback з** `ErrorBoundary` ("Error loading data"). --- ## Приклад з `React.lazy()` ```javascript const UserProfile = React.lazy(() => import("./UserProfile")); ``` Тут `React.lazy()` сам викидає `Promise` під час завантаження, тому Suspense "підхопить" цей проміс і покаже свій fallback. --- ## Приклад вкладених Suspense + ErrorBoundary Ти можеш обгортати окремі ділянки UI: ```javascript function Dashboard() { return ( <div> <ErrorBoundary fallback={<h3>Error in stats</h3>}> <Suspense fallback={<p>Loading stats...</p>}> <StatsWidget /> </Suspense> </ErrorBoundary> <ErrorBoundary fallback={<h3>Error in profile</h3>}> <Suspense fallback={<p>Loading profile...</p>}> <ProfileWidget /> </Suspense> </ErrorBoundary> </div> ); } ``` Якщо `StatsWidget` ламається -> показується "Error in stats", а `ProfileWidget` залишається недоторканим. Якщо `StatsWidget` просто вантажиться -> "Loading stats...". Усе незалежно. --- ## Помилка новачків - навпаки вкласти ```javascript <Suspense fallback={<p>Loading...</p>}> <ErrorBoundary fallback={<p>Error!</p>}> <UserProfile /> </ErrorBoundary> </Suspense> ``` Так **теж працює**, але є нюанс: якщо помилка станеться *до того, як Suspense відпрацює Promise*, React може не встигнути показати "завантаження", а одразу покаже "помилку". Тому **зазвичай ErrorBoundary має бути "зовні"**, щоб зловити будь-які помилки всередині Suspense-зони. Хоча іноді (наприклад, для SSR або split-завантаження) - навпаки. --- ## Резюме: хто за що відповідає | Ситуація | Хто відпрацює | Що покаже | |---|---|---| | Компонент вантажиться (lazy, data) | `Suspense` | fallback-завантаження | | Компонент викинув помилку (`throw new Error()`) | `ErrorBoundary` | fallback-помилка | | Помилка поза React (подія, async код) | - | потрібен try/catch вручну | | Обидві ситуації можливі | **Комбо** | `Suspense` при завантаженні -> `ErrorBoundary` при помилці | --- ## Рекомендований патерн (React 18+) ```javascript <ErrorBoundary fallback={<ErrorUI />}> <Suspense fallback={<LoadingUI />}> <AsyncComponent /> </Suspense> </ErrorBoundary> ``` Таким чином: - Завантаження -> `LoadingUI` - Помилка -> `ErrorUI` - Успішний результат -> `AsyncComponent` --- ## Патерн для UI-зон (кращий підхід для великих застосунків) | UI-зона | ErrorBoundary | Suspense | |---|---|---| | Головна сторінка | спільний ErrorBoundary | спільний Suspense | | Окремі віджети | локальні ErrorBoundary | локальні Suspense | | Критичні зони (checkout, auth) | окремі ErrorBoundary | Suspense для даних | --- ## Підсумок > **Так**, ErrorBoundary і Suspense чудово працюють **разом**. > Використовуй: > > - `<Suspense>` -> для *завантаження* (коли компонент ще не готовий), > - `<ErrorBoundary>` -> для *помилок* (коли компонент впав). Рекомендований порядок вкладеності: ```javascript <ErrorBoundary> <Suspense> <Component /> </Suspense> </ErrorBoundary> ``` Такий патерн: - ізолює помилки; - показує fallback UI при завантаженні і збоях; - робить інтерфейс стійким і плавним.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.