Skip to main content
Practice Problems

Error boundaries in React

What are Error Boundaries?

Error Boundaries are React components that catch JavaScript errors in their child component tree, log them, and display a fallback UI instead of crashing the entire application.


Why use Error Boundaries?

Before Error Boundaries, an error in one component would break the entire app. Error Boundaries allow you to:

  • Prevent the entire application from crashing
  • Show users a friendly error message
  • Log errors for analysis
  • Isolate problematic parts of the application

Creating an Error Boundary

An Error Boundary is a class component with getDerivedStateFromError and/or componentDidCatch methods.

javascript
import React from 'react'; class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // Update state to show fallback UI return { hasError: true }; } componentDidCatch(error, errorInfo) { // Log error to reporting service console.error('Error caught by boundary:', error, errorInfo); } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } }

Usage

Wrap components that might throw errors:

javascript
function App() { return ( <div> <ErrorBoundary> <MyWidget /> </ErrorBoundary> <ErrorBoundary> <AnotherWidget /> </ErrorBoundary> </div> ); }

If MyWidget throws an error, only it will crash while AnotherWidget continues working.


Difference between methods

getDerivedStateFromError

Called during rendering phase. Used to update state and show fallback UI.

javascript
static getDerivedStateFromError(error) { // Must return an object to update state return { hasError: true, error }; }

componentDidCatch

Called after rendering. Used for logging errors.

javascript
componentDidCatch(error, errorInfo) { // errorInfo.componentStack contains the component call stack logErrorToService(error, errorInfo); }

Advanced Example

javascript
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false, error: null, errorInfo: null }; } static getDerivedStateFromError(error) { return { hasError: true }; } componentDidCatch(error, errorInfo) { this.setState({ error, errorInfo }); // Send to monitoring service logErrorToService(error, errorInfo); } handleReset = () => { this.setState({ hasError: false, error: null, errorInfo: null }); }; render() { if (this.state.hasError) { return ( <div className="error-container"> <h2>An error occurred</h2> <details> <summary>Details</summary> <p>{this.state.error && this.state.error.toString()}</p> <pre>{this.state.errorInfo && this.state.errorInfo.componentStack}</pre> </details> <button onClick={this.handleReset}> Try again </button> </div> ); } return this.props.children; } }

What Error Boundaries DON'T catch

Error Boundaries catch errors in:

  • Render methods
  • Lifecycle methods
  • Constructors of child components

They DON'T catch:

  • Event handlers
  • Asynchronous code (setTimeout, Promise)
  • Server-side rendering errors
  • Errors in the Error Boundary itself

Event Handlers

Use regular try-catch for event handlers:

javascript
function MyComponent() { function handleClick() { try { // Code that might throw an error somethingDangerous(); } catch (error) { console.error('Error in click handler:', error); } } return <button onClick={handleClick}>Click me</button>; }

Asynchronous Errors

Use try-catch for asynchronous errors as well:

javascript
function MyComponent() { async function fetchData() { try { const response = await fetch('/api/data'); const data = await response.json(); // ... } catch (error) { console.error('Fetch error:', error); } } useEffect(() => { fetchData(); }, []); return <div>...</div>; }

Where to place Error Boundaries

Global Level

javascript
function App() { return ( <ErrorBoundary> <Router> <Layout> <Routes /> </Layout> </Router> </ErrorBoundary> ); }

Route Level

javascript
function App() { return ( <Router> <ErrorBoundary> <Route path="/profile" element={<Profile />} /> </ErrorBoundary> <ErrorBoundary> <Route path="/settings" element={<Settings />} /> </ErrorBoundary> </Router> ); }

Component Level

javascript
function Dashboard() { return ( <div> <ErrorBoundary> <ChartWidget /> </ErrorBoundary> <ErrorBoundary> <StatsWidget /> </ErrorBoundary> </div> ); }

Integration with monitoring services

Sentry

javascript
import * as Sentry from '@sentry/react'; class ErrorBoundary extends React.Component { componentDidCatch(error, errorInfo) { Sentry.captureException(error, { contexts: { react: errorInfo } }); } // ... } // Or use Sentry's built-in ErrorBoundary import { ErrorBoundary } from '@sentry/react'; function App() { return ( <ErrorBoundary fallback={<ErrorFallback />}> <MyApp /> </ErrorBoundary> ); }

React 18 and useErrorBoundary

React doesn't have a hook for Error Boundaries yet, but libraries offer solutions:

react-error-boundary

javascript
import { ErrorBoundary, useErrorHandler } from 'react-error-boundary'; function ErrorFallback({ error, resetErrorBoundary }) { return ( <div role="alert"> <p>Something went wrong:</p> <pre>{error.message}</pre> <button onClick={resetErrorBoundary}>Try again</button> </div> ); } function App() { return ( <ErrorBoundary FallbackComponent={ErrorFallback} onReset={() => { // Reset app state }} onError={(error, errorInfo) => { // Log error }} > <MyApp /> </ErrorBoundary> ); } // Use in functional components function MyComponent() { const handleError = useErrorHandler(); async function fetchData() { try { const response = await fetch('/api/data'); if (!response.ok) throw new Error('Failed to fetch'); return response.json(); } catch (error) { handleError(error); } } // ... }

Best Practices

Multiple Error Boundaries

Don't use a single global Error Boundary. Use multiple at different levels:

javascript
function App() { return ( <ErrorBoundary fallback={<GlobalError />}> <Header /> <ErrorBoundary fallback={<SidebarError />}> <Sidebar /> </ErrorBoundary> <ErrorBoundary fallback={<ContentError />}> <Content /> </ErrorBoundary> <Footer /> </ErrorBoundary> ); }

Informative Messages

Show users helpful information:

javascript
function ErrorFallback({ error }) { return ( <div className="error-page"> <h1>Oops! Something went wrong</h1> <p>We're working on fixing this.</p> <p>Try:</p> <ul> <li>Refreshing the page</li> <li>Going back to home</li> <li>Reporting the issue to us</li> </ul> {process.env.NODE_ENV === 'development' && ( <details> <summary>Technical details</summary> <pre>{error.message}</pre> </details> )} </div> ); }

Recovery Options

Give users a way to try again:

javascript
class ErrorBoundary extends React.Component { state = { hasError: false, errorCount: 0 }; static getDerivedStateFromError(error) { return { hasError: true }; } componentDidUpdate(prevProps) { // Reset error when children change if (this.state.hasError && prevProps.children !== this.props.children) { this.setState({ hasError: false, errorCount: 0 }); } } handleReset = () => { this.setState(state => ({ hasError: false, errorCount: state.errorCount + 1 })); }; render() { if (this.state.hasError) { return ( <div> <h1>Error</h1> <button onClick={this.handleReset}>Try again</button> {this.state.errorCount > 2 && ( <p>If the problem persists, please contact support.</p> )} </div> ); } return this.props.children; } }

Conclusion

Error Boundaries:

  • Catch errors in React components
  • Must be class components
  • Use getDerivedStateFromError and componentDidCatch
  • Don't catch errors in event handlers and async code
  • Best to use multiple at different levels
  • Allow showing fallback UI instead of blank screen
  • Essential for production applications

In interviews:

Important to be able to:

  • Explain what Error Boundaries are
  • Show how to create an Error Boundary
  • Describe which errors they don't catch
  • Explain the difference between getDerivedStateFromError and componentDidCatch
  • Give examples of proper Error Boundary placement

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?
Practice Problems