- Home
- /
- Tutorials
- /
- React Tutorial
- /
- Error Boundaries
Data and Errors
Error Boundaries
An uncaught error during render does not break one component - React unmounts the entire tree, and the user gets a blank page. An error boundary is the only thing that stops that.
Why a blank page
React cannot know which parts of a half-rendered tree are still trustworthy, so it takes the safe option and removes everything. That is deliberate, and it means one careless user.name on a null user can take down the whole app.
A boundary catches it
An error boundary is a component that catches errors thrown while rendering anything below it and shows a fallback instead. It is the one thing still written as a class - there is no hook equivalent, because the lifecycle it needs has none.
A boundary and a crash
jsx
class ErrorBoundary extends React.Component {
constructor(props) {
super(props)
this.state = { error: null }
}
// Called when a child throws during render.
static getDerivedStateFromError(error) {
return { error }
}
render() {
if (this.state.error) {
return (
<div style={{ border: "1px solid #fecaca", background: "#fef2f2", padding: 10, borderRadius: 8 }}>
<strong>Something went wrong.</strong>
<p style={{ margin: "6px 0 0", color: "#b91c1c" }}>{this.state.error.message}</p>
<button onClick={() => this.setState({ error: null })}>Try again</button>
</div>
)
}
return this.props.children
}
}
function Risky({ crash }) {
if (crash) throw new Error("A component threw while rendering")
return <p style={{ color: "#15803d" }}>Rendering normally.</p>
}
function Demo() {
const [crash, setCrash] = React.useState(false)
return (
<div>
<button onClick={() => setCrash(true)}>Make it crash</button>
<p>The rest of the page keeps working.</p>
<ErrorBoundary>
<Risky crash={crash} />
</ErrorBoundary>
</div>
)
}
const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<Demo />)Press the button: the risky component is replaced by the fallback, and everything outside the boundary carries on. Without it, the whole preview would go blank.
What it does not catch
- Event handlers - use
try/catch; nothing is rendering when a click fires. - Async code - a rejected promise or a
setTimeoutcallback is outside the render pass. - Errors in the boundary itself - it cannot catch its own.
- Server rendering - a different mechanism applies there.
So a boundary is for rendering failures. A failed request is not one - that is the error state from the previous lesson, handled by ordinary code.
Where to put them
One at the root stops the blank page. Additional ones around independent regions - a sidebar, a widget, a route - keep a failure local, so a broken chart does not take the navigation with it.
In real projects most people use react-error-boundary rather than writing the class, since it adds retry and reset handling. Knowing what the class does first makes that library obvious rather than magic.
