Skip to main content

ErrorBoundary і Suspense

Різниця між 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)Suspensefallback-завантаження
Компонент викинув помилку (throw new Error())ErrorBoundaryfallback-помилка
Помилка поза React (подія, async код)-потрібен try/catch вручну
Обидві ситуації можливіКомбоSuspense при завантаженні -> ErrorBoundary при помилці

Рекомендований патерн (React 18+)

javascript
<ErrorBoundary fallback={<ErrorUI />}> <Suspense fallback={<LoadingUI />}> <AsyncComponent /> </Suspense> </ErrorBoundary>

Таким чином:

  • Завантаження -> LoadingUI
  • Помилка -> ErrorUI
  • Успішний результат -> AsyncComponent

Патерн для UI-зон (кращий підхід для великих застосунків)

UI-зонаErrorBoundarySuspense
Головна сторінкаспільний ErrorBoundaryспільний Suspense
Окремі віджетилокальні ErrorBoundaryлокальні Suspense
Критичні зони (checkout, auth)окремі ErrorBoundarySuspense для даних

Підсумок

Так, ErrorBoundary і Suspense чудово працюють разом. Використовуй:

  • <Suspense> -> для завантаження (коли компонент ще не готовий),
  • <ErrorBoundary> -> для помилок (коли компонент впав).

Рекомендований порядок вкладеності:

javascript
<ErrorBoundary> <Suspense> <Component /> </Suspense> </ErrorBoundary>

Такий патерн:

  • ізолює помилки;
  • показує fallback UI при завантаженні і збоях;
  • робить інтерфейс стійким і плавним.

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

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

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