Loading...
Loading...
By continuing to use the platform, you accept the terms of the Privacy Policy and the use of cookies.
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.
Before Error Boundaries, an error in one component would break the entire app. Error Boundaries allow you to:
An Error Boundary is a class component with getDerivedStateFromError and/or componentDidCatch methods.
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;
}
}
Wrap components that might throw errors:
function App() {
return (
<div>
<ErrorBoundary>
<MyWidget />
</ErrorBoundary>
<ErrorBoundary>
<AnotherWidget />
</ErrorBoundary>
</div>
);
}
If MyWidget throws an error, only it will crash while AnotherWidget continues working.
Called during rendering phase. Used to update state and show fallback UI.
static getDerivedStateFromError(error) {
// Must return an object to update state
return { hasError: true, error };
}
Called after rendering. Used for logging errors.
componentDidCatch(error, errorInfo) {
// errorInfo.componentStack contains the component call stack
logErrorToService(error, errorInfo);
}
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;
}
}
Error Boundaries catch errors in:
They DON'T catch:
Use regular try-catch for event handlers:
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>;
}
Use try-catch for asynchronous errors as well:
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>;
}
function App() {
return (
<ErrorBoundary>
<Router>
<Layout>
<Routes />
</Layout>
</Router>
</ErrorBoundary>
);
}
function App() {
return (
<Router>
<ErrorBoundary>
<Route path="/profile" element={<Profile />} />
</ErrorBoundary>
<ErrorBoundary>
<Route path="/settings" element={<Settings />} />
</ErrorBoundary>
</Router>
);
}
function Dashboard() {
return (
<div>
<ErrorBoundary>
<ChartWidget />
</ErrorBoundary>
<ErrorBoundary>
<StatsWidget />
</ErrorBoundary>
</div>
);
}
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 doesn't have a hook for Error Boundaries yet, but libraries offer solutions:
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);
}
}
// ...
}
Don't use a single global Error Boundary. Use multiple at different levels:
function App() {
return (
<ErrorBoundary fallback={<GlobalError />}>
<Header />
<ErrorBoundary fallback={<SidebarError />}>
<Sidebar />
</ErrorBoundary>
<ErrorBoundary fallback={<ContentError />}>
<Content />
</ErrorBoundary>
<Footer />
</ErrorBoundary>
);
}
Show users helpful information:
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>
);
}
Give users a way to try again:
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;
}
}
Error Boundaries:
getDerivedStateFromError and componentDidCatchIn interviews:
Important to be able to:
getDerivedStateFromError and componentDidCatch