Handling errors in a React app isn't just about keeping it from crashing; it’s about controlling the blast radius. A common mistake is placing error boundaries in the wrong spots. Putting a single boundary at the root is risky—one small failure in a chart component can wipe out the entire page, leaving nothing but a blank screen. On the other hand, wrapping every single tiny component in a boundary will just clutter the UI with annoying error messages.
The trick is granularity based on risk. Use built-in framework features, like
Next.js's error.tsx, for major features or entire pages. But for third-party
components or widgets with unstable data—like charts or editors—wrap them
individually at the component level.
It’s also important to know the limits of an error boundary. It only catches
errors during rendering, lifecycle methods, or inside a constructor. It won’t
catch errors in event handlers (like a button click) or failed fetch calls.
For those, you still need try/catch or manual error logic. You also have to
distinguish between error types; a predictable network failure requires a
different approach than a crash that happens while the app is drawing the UI.
User experience (UX) should always come first. Showing technical jargon like
TypeError: cannot read property 'map' of undefined doesn't help anyone.
Instead, provide a human fallback UI: explain what happened, show which parts of
the app are still working, and give them a retry button.
Your strategy should vary. Use toasts for minor hiccups and error boundaries for fatal component failures. The goal isn't just to prevent a crash, but to make sure the user doesn't feel like the whole app is broken just because one small part is acting up.
Happy experimenting with your app's error structure!