Suggest an editImprove this articleRefine the answer for “ErrorBoundary and Suspense”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)Yes, `ErrorBoundary` and `Suspense` work great together: React handles both a `Promise` and an `Error` the same way, through a "throw", except a `Promise` leads to `Suspense`'s fallback (waiting), while an `Error` leads to `ErrorBoundary`'s fallback (failure). **Key point:** the recommended nesting order is `<ErrorBoundary><Suspense><Component /></Suspense></ErrorBoundary>`, so the ErrorBoundary catches any errors inside the Suspense zone.Shown above the full answer for quick recall.Answer (EN)Image## Difference between Suspense and Error Boundary | Component | What it does | When it triggers | |---|---|---| | `<Suspense>` | Shows a **fallback** while the component **isn't ready yet** (for example, loading data or code). | When the component "suspends" (throws a *Promise*). | | `<ErrorBoundary>` | Shows a **fallback on error**, when the component has **crashed**. | When the component "crashes" (throws an *Error*). | > React handles both a `Promise` and an `Error` the same way, through a "throw". > The difference is *what exactly was thrown*: > - a `Promise` means waiting (Suspense) > - an `Error` means showing an error (ErrorBoundary) --- ## How they work together React goes top to bottom: 1. A component can **suspend** the render (throw a `Promise`) -> React looks for the nearest `<Suspense>`. 2. If a component **crashes** (throws an `Error`) -> React looks for the nearest `<ErrorBoundary>`. So they can, and should, be **nested** inside each other so that different situations (loading and errors) are handled correctly. --- ## Example of a correct combination ```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> ); } ``` What happens: - if `UserProfile` *isn't loaded yet* (for example, `React.lazy()` or a Suspense-enabled request), the **fallback from** `Suspense` shows ("Loading..."); - if `UserProfile` *throws an error* (for example, `throw new Error()`), the **fallback from** `ErrorBoundary` shows ("Error loading data"). --- ## An example with `React.lazy()` ```javascript const UserProfile = React.lazy(() => import("./UserProfile")); ``` Here `React.lazy()` itself throws a `Promise` while loading, so Suspense "catches" that promise and shows its fallback. --- ## An example of nested Suspense + ErrorBoundary You can wrap individual UI areas: ```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> ); } ``` If `StatsWidget` breaks, "Error in stats" shows, while `ProfileWidget` stays untouched. If `StatsWidget` is simply loading, "Loading stats..." shows. Everything is independent. --- ## A beginner mistake: nesting it the other way ```javascript <Suspense fallback={<p>Loading...</p>}> <ErrorBoundary fallback={<p>Error!</p>}> <UserProfile /> </ErrorBoundary> </Suspense> ``` This **also works**, but there's a nuance: if an error happens *before Suspense resolves the Promise*, React might not have time to show "loading" and shows "error" right away instead. So **ErrorBoundary usually has to be on the outside**, to catch any errors inside the Suspense zone. Though sometimes (for example, with SSR or split loading) it's the other way around. --- ## Summary: who is responsible for what | Situation | Who handles it | What it shows | |---|---|---| | The component is loading (lazy, data) | `Suspense` | a loading fallback | | The component threw an error (`throw new Error()`) | `ErrorBoundary` | an error fallback | | An error outside React (an event, async code) | - | needs a manual try/catch | | Both situations are possible | **Combined** | `Suspense` while loading -> `ErrorBoundary` on error | --- ## Recommended pattern (React 18+) ```javascript <ErrorBoundary fallback={<ErrorUI />}> <Suspense fallback={<LoadingUI />}> <AsyncComponent /> </Suspense> </ErrorBoundary> ``` This way: - Loading -> `LoadingUI` - Error -> `ErrorUI` - Successful result -> `AsyncComponent` --- ## A pattern for UI zones (best approach for large applications) | UI zone | ErrorBoundary | Suspense | |---|---|---| | The main page | a shared ErrorBoundary | a shared Suspense | | Individual widgets | local ErrorBoundaries | local Suspense | | Critical zones (checkout, auth) | separate ErrorBoundaries | Suspense for data | --- ## Summary > **Yes**, ErrorBoundary and Suspense work great **together**. > Use: > > - `<Suspense>` for *loading* (when the component isn't ready yet), > - `<ErrorBoundary>` for *errors* (when the component has crashed). Recommended nesting order: ```javascript <ErrorBoundary> <Suspense> <Component /> </Suspense> </ErrorBoundary> ``` This pattern: - isolates errors; - shows a fallback UI during loading and failures; - makes the interface resilient and smooth.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.