Overview
The ErrorBoundary component is a React error boundary that catches JavaScript errors anywhere in the component tree, logs them, and displays a fallback UI instead of crashing the entire application.
Usage
import { ErrorBoundary } from '@/components'
function App () {
return (
< ErrorBoundary >
< YourApp />
</ ErrorBoundary >
)
}
Props
The component tree to protect with the error boundary
Optional custom fallback UI to display when an error occurs. If not provided, the default ErrorPage component is used.
Features
Error Catching
The error boundary catches errors during:
Rendering
Lifecycle methods
Constructors of child components
static getDerivedStateFromError ( error ) {
return { hasError: true , error }
}
Error Logging
Errors are automatically logged to the console:
componentDidCatch ( error , errorInfo ) {
console . error ( "Uncaught error:" , error , errorInfo )
}
Error Recovery
The component provides a resetErrorBoundary method to attempt recovery:
resetErrorBoundary = () => {
this . setState ({ hasError: false , error: null })
}
Default Error UI
If no custom fallback is provided, the component displays an ErrorPage with:
Error icon
User-friendly message in Spanish
Error details (in development)
“Try again” button
“Return home” link
Component Structure
ErrorBoundary Component
ErrorPage Component
import { Component } from 'react'
import { ErrorPage } from './ErrorPage'
export class ErrorBoundary extends Component {
constructor ( props ) {
super ( props )
this . state = { hasError: false , error: null }
}
static getDerivedStateFromError ( error ) {
return { hasError: true , error }
}
componentDidCatch ( error , errorInfo ) {
console . error ( "Uncaught error:" , error , errorInfo )
}
resetErrorBoundary = () => {
this . setState ({ hasError: false , error: null })
}
render () {
if ( this . state . hasError ) {
if ( this . props . fallback ) {
return this . props . fallback
}
return < ErrorPage error = { this . state . error } resetErrorBoundary = { this . resetErrorBoundary } />
}
return this . props . children
}
}
Usage Patterns
App-Level Boundary
Wrap your entire application:
import { ErrorBoundary } from '@/components'
function App () {
return (
< ErrorBoundary >
< Router >
< Routes >
< Route path = "/" element = { < Home /> } />
< Route path = "/jobs" element = { < Jobs /> } />
</ Routes >
</ Router >
</ ErrorBoundary >
)
}
Route-Level Boundaries
Wrap individual routes for isolated error handling:
import { ErrorBoundary } from '@/components'
function Routes () {
return (
<>
< Route path = "/" element = { < Home /> } />
< Route
path = "/jobs"
element = {
< ErrorBoundary >
< Jobs />
</ ErrorBoundary >
}
/>
< Route
path = "/jobs/:id"
element = {
< ErrorBoundary >
< JobDetail />
</ ErrorBoundary >
}
/>
</>
)
}
Component-Level Boundaries
Wrap specific components:
import { ErrorBoundary } from '@/components'
function Dashboard () {
return (
< div >
< Header />
< ErrorBoundary >
< JobListings jobs = { jobs } />
</ ErrorBoundary >
< ErrorBoundary >
< UserProfile />
</ ErrorBoundary >
< Footer />
</ div >
)
}
Custom Fallback UI
import { ErrorBoundary } from '@/components'
function CustomErrorFallback () {
return (
< div className = "error-container" >
< h2 > Something went wrong </ h2 >
< p > Please refresh the page or contact support. </ p >
</ div >
)
}
function App () {
return (
< ErrorBoundary fallback = { < CustomErrorFallback /> } >
< YourApp />
</ ErrorBoundary >
)
}
With Error Reporting Service
import { Component } from 'react'
import * as Sentry from '@sentry/react'
export class ErrorBoundary extends Component {
// ... existing code ...
componentDidCatch ( error , errorInfo ) {
// Log to console
console . error ( "Uncaught error:" , error , errorInfo )
// Report to error tracking service
Sentry . captureException ( error , {
contexts: {
react: {
componentStack: errorInfo . componentStack
}
}
})
}
// ... rest of component ...
}
Error Recovery Strategies
Automatic Retry
import { ErrorBoundary } from '@/components'
import { useEffect , useState } from 'react'
function AutoRetryBoundary ({ children }) {
const [ retryCount , setRetryCount ] = useState ( 0 )
useEffect (() => {
if ( retryCount > 0 && retryCount < 3 ) {
const timer = setTimeout (() => {
window . location . reload ()
}, 2000 )
return () => clearTimeout ( timer )
}
}, [ retryCount ])
return (
< ErrorBoundary
onError = { () => setRetryCount ( c => c + 1 ) }
>
{ children }
</ ErrorBoundary >
)
}
Reset on Route Change
import { ErrorBoundary } from '@/components'
import { useLocation } from 'react-router-dom'
import { useEffect , useRef } from 'react'
function RouterErrorBoundary ({ children }) {
const location = useLocation ()
const boundaryRef = useRef ()
useEffect (() => {
// Reset error boundary when route changes
if ( boundaryRef . current ?. resetErrorBoundary ) {
boundaryRef . current . resetErrorBoundary ()
}
}, [ location . pathname ])
return (
< ErrorBoundary ref = { boundaryRef } >
{ children }
</ ErrorBoundary >
)
}
What Error Boundaries Don’t Catch
Error boundaries do NOT catch errors in:
Event handlers - Use try-catch instead
Asynchronous code - Use .catch() or try-catch in async functions
Server-side rendering
Errors in the error boundary itself
Handling Event Handler Errors
function MyComponent () {
const [ error , setError ] = useState ( null )
const handleClick = () => {
try {
// Code that might throw
riskyOperation ()
} catch ( error ) {
setError ( error )
console . error ( 'Event handler error:' , error )
}
}
if ( error ) {
return < div > Error: { error . message } </ div >
}
return < button onClick = { handleClick } > Click me </ button >
}
Handling Async Errors
function AsyncComponent () {
const [ error , setError ] = useState ( null )
useEffect (() => {
fetchData ()
. catch ( error => {
setError ( error )
console . error ( 'Async error:' , error )
})
}, [])
if ( error ) {
return < div > Error: { error . message } </ div >
}
return < div > Content </ div >
}
Styling
The ErrorPage component uses CSS modules (ErrorPage.module.css):
styles.container - Full-page error container
styles.content - Centered content wrapper
styles.icon - Error icon styling
styles.title - Error title
styles.message - Error message
styles.errorDetails - Technical error details
styles.actions - Action buttons container
styles.retryButton - Retry button
styles.homeButton - Home link button
Source Code
Locations:
ErrorBoundary: src/components/ErrorBoundary/ErrorBoundary.jsx:4
ErrorPage: src/components/ErrorBoundary/ErrorPage.jsx:4
Components Overview View all available components
Loading Loading states for better UX
Best Practices
Use multiple boundaries - Don’t wrap everything in one boundary; isolate errors to specific sections
Provide context - Show users what went wrong and what they can do
Log errors - Always log to console and consider error tracking services
Test error states - Intentionally throw errors during development to verify boundaries work
Recovery options - Always provide a way for users to recover (retry, go home, etc.)
Production vs Development - Show detailed errors in development, friendly messages in production
Testing
Trigger Errors for Testing
function BuggyComponent () {
const [ throwError , setThrowError ] = useState ( false )
if ( throwError ) {
throw new Error ( 'Test error for error boundary' )
}
return (
< button onClick = { () => setThrowError ( true ) } >
Trigger Error
</ button >
)
}
// Usage
< ErrorBoundary >
< BuggyComponent />
</ ErrorBoundary >
Accessibility
Error messages are clear and in plain language
Action buttons are keyboard accessible
Semantic HTML for better screen reader support
Links and buttons have descriptive text