Bootcamp
Search…
7.8: Error Boundaries
Error boundary components are a kind of "higher-order component". Higher-order components are components whose tags surround and apply logic to child components, for example how <div> opening and closing tags surround child elements in HTML.
React recommends creating error boundary components in your app so that if and when there is an error, your app doesn't disappear off the page when there's a rendering error (which it will if nothing else is done).
This component will be written in class syntax, since React has not implemented the same functionality yet in hooks. See more on that here: https://reactjs.org/docs/hooks-faq.html#do-hooks-cover-all-use-cases-for-classes​

Class Components

Class components are the older way to write React apps.
To write a React class component we define a JavaScript class. The state of this component is kept as class attributes. Each time the JSX declares a component, an instance of the class is created inside React.
Class components and hooks components can be used together in the same app.
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
See the full docs on class components here: https://reactjs.org/docs/components-and-props.html​

setState

In class components state works differently. There is only one library method that sets state inside a component, which is called setState. Class component state is always an object and it is set entirely by this function.
class Counter extends React.Component {
constructor(props) {
super(props);
​
// create the default state value when the component is initialized
this.state = { count: 0 };
this.increment = this.increment.bind(this);
}
​
// note the lack of the word function or function
// definition. this is a class method
increment() {
// update the state
this.setState({ count: this.state.count + 1 });
}
​
// render is the class method called when the DOM updates
render() {
// render always returns JSX
return (
<div>
<h1>Hello, world!</h1>
<h2>Count is {this.state.count}.</h2>
<p>
<button onClick={this.increment}>add one to count</button>
</p>
</div>
);
}
}
Read more about state here: https://reactjs.org/docs/state-and-lifecycle.html​

Lifecycle Methods

In class components there are methods that will get called depending on what React is doing to that component. These are essentially callbacks that happen when, for example, React is done manipulating the DOM after a state change.
Read about all the class component lifecycle methods here: https://reactjs.org/docs/state-and-lifecycle.html​

ErrorBoundary

componentDidCatch is a special lifecycle method that runs when React has detected that there was a runtime exception in the component.
When we create a component with this lifecycle method defined inside, it means we can create a Higher Order Component for the purpose of catching errors in the app. Any errors that happen in the children of this component will cause componentDidCatch to run and will prevent the app from crashing. React strongly suggests that this is implemented at least once for every app to avoid the case where the entire app will crash and cease to run without any user messaging or error handling.

Example

class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
​
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
// logErrorToMyService(error, errorInfo);
console.log(error, errorInfo);
this.setState({ hasError: true });
}
​
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}
​
// props.children refers to line 2 below, where
// we specify the contents of the error boundary component
// there is no error, render MyWidget
return this.props.children;
}
}
Use the error boundary higher-order component to catch errors from MyWidget.
<ErrorBoundary>
<MyWidget />
</ErrorBoundary>

Full Error Example

First, we need to have a React app that is set up differently from normal. This is because in development mode React will catch errors and display them in the console and on screen.
The error behaviour we are discussing would only happen in a production setting.
This repo has a React app with no Fast Refresh or dev server: https://github.com/rocketacademy/react-error-boundary-bootcamp​
Inside is a component that will throw a runtime React rendering error. bootcamp https://github.com/rocketacademy/react-error-boundary-bootcamp/blob/main/src/App.jsx​
import React, { useState } from 'react';
​
function Counter() {
const [count, setCount] = useState(0);
​
const incrementCount = (event) => {
console.log(`current value of count is: ${count}`);
​
// call the hooks function when we want to manipulate the DOMM.
setCount(count + 1);
};
​
console.log('counter function component');
if (count > 3) {
// make a runtime rendering error, assign the click event to something else
incrementCount = <h1>This assignment causes error!!!! :(</h1>;
}
​
return (
<div>
<p>You clicked {count} times</p>
<button onClick={incrementCount}>Click me</button>
</div>
);
}
​
export default function App() {
console.log('App');
return (
<div>
This is App.jsx
<Counter />
</div>
);
}
To run this app, start the Webpack build/watch:
npm run watch
In .a separate terminal start the Express.js app:
node index.mjs
When the counter is above 3 the app crashes. Notice that in the dev tools the entire React app empties out of the root div.
See a codesandbox example of the blank screen here: https://codesandbox.io/s/ra-react-error-boundary-1-6odmq​

Full Error Boundary Example

This repo implements an error boundary component that catches the error and, instead of silently crashing, shows a message to the user.
See a codesandbox example here:

Counter Component

function Counter() {
const [count, setCount] = useState(0);
​
const incrementCount = (event) => {
console.log(`current value of count is: ${count}`);
​
// call the hooks function when we want to manipulate the DOMM.
setCount(count + 1);
};
​
console.log('counter function component');
if (count > 3) {
// make a runtime rendering error, assign the click event to something else
incrementCount = <h1>This assignment causes error!!!! :(</h1>;
}
​
return (
<div>
<p>You clicked {count} times</p>
<button onClick={incrementCount}>Click me</button>
</div>
);
}

Error Boundary

class CounterErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
​
componentDidCatch(error, errorInfo) {
console.log('error detected! we are setting state');
this.setState({ hasError: true });
}
​
render() {
if (this.state.hasError) {
console.log('rendering error');
// You can render any custom fallback UI
return <h1>Something went wrong inside counter!!</h1>;
}
​
// in this example this.props.children is Counter component used
// below in the App component
return this.props.children;
}
}

App

export default function App() {
console.log('App');
return (
<div>
This is App.jsx
<CounterErrorBoundary>
<Counter />
</CounterErrorBoundary>
</div>
);
}
See more about error boundaries in the docs: https://reactjs.org/docs/error-boundaries.html​
Copy link
On this page
Class Components
setState
Lifecycle Methods
ErrorBoundary
Example
Full Error Example
Full Error Boundary Example