Bootcamp
Search…
📅
Course Schedule
0: Language and Tooling Teaching Guide
1: Frontend Basics Teaching Guide
2: Backend Basics Teaching Guide
3: Backend Applications Teaching Guide
4: Backend Structure Teaching Guide
5: Full-Stack Applications Teaching Guide
6: Frontend Infrastructure Teaching Guide
7: React Teaching Guide
8: Advanced React Teaching Guide
9: Advanced Topics Teaching Guide
🧮
Algorithms Teaching Guide
💼
Interview Prep Teaching Guide
☺
User Experience Teaching Guide
7.8: Error Boundaries
Error boundary components are a kind of Higher Order component. Higher-order component just means a component that is written in a different style so that it has opening and closing tags in the JSX- surrounding some child JSX.
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.
1
class Welcome extends React.Component {
2
render() {
3
return <h1>Hello, {this.props.name}</h1>;
4
}
5
}
Copied!
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.
1
class Counter extends React.Component {
2
constructor(props) {
3
super(props);
4
​
5
// create the default state value when the component is initialized
6
this.state = { count: 0 };
7
this.increment = this.increment.bind(this);
8
}
9
​
10
// note the lack of the word function or function
11
// definition. this is a class method
12
increment() {
13
// update the state
14
this.setState({ count: this.state.count + 1 });
15
}
16
​
17
// render is the class method called when the DOM updates
18
render() {
19
// render always returns JSX
20
return (
21
<div>
22
<h1>Hello, world!</h1>
23
<h2>Count is {this.state.count}.</h2>
24
<p>
25
<button onClick={this.increment}>add one to count</button>
26
</p>
27
</div>
28
);
29
}
30
}
Copied!
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

1
class ErrorBoundary extends React.Component {
2
constructor(props) {
3
super(props);
4
this.state = { hasError: false };
5
}
6
​
7
componentDidCatch(error, errorInfo) {
8
// You can also log the error to an error reporting service
9
// logErrorToMyService(error, errorInfo);
10
console.log(error, errorInfo);
11
this.setState({ hasError: true });
12
}
13
​
14
render() {
15
if (this.state.hasError) {
16
// You can render any custom fallback UI
17
return <h1>Something went wrong.</h1>;
18
}
19
​
20
// props.children refers to line 2 below, where
21
// we specify the contents of the error boundary component
22
// there is no error, render MyWidget
23
return this.props.children;
24
}
25
}
Copied!
Use the error boundary higher-order component to catch errors from MyWidget.
1
<ErrorBoundary>
2
<MyWidget />
3
</ErrorBoundary>
Copied!

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​
1
import React, { useState } from 'react';
2
​
3
function Counter() {
4
const [count, setCount] = useState(0);
5
​
6
const incrementCount = (event) => {
7
console.log(`current value of count is: ${count}`);
8
​
9
// call the hooks function when we want to manipulate the DOMM.
10
setCount(count + 1);
11
};
12
​
13
console.log('counter function component');
14
if (count > 3) {
15
// make a runtime rendering error, assign the click event to something else
16
incrementCount = <h1>This assignment causes error!!!! :(</h1>;
17
}
18
​
19
return (
20
<div>
21
<p>You clicked {count} times</p>
22
<button onClick={incrementCount}>Click me</button>
23
</div>
24
);
25
}
26
​
27
export default function App() {
28
console.log('App');
29
return (
30
<div>
31
This is App.jsx
32
<Counter />
33
</div>
34
);
35
}
Copied!
To run this app, start the Webpack build/watch:
1
npm run watch
Copied!
In .a separate terminal start the Express.js app:
1
node index.mjs
Copied!
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

1
function Counter() {
2
const [count, setCount] = useState(0);
3
​
4
const incrementCount = (event) => {
5
console.log(`current value of count is: ${count}`);
6
​
7
// call the hooks function when we want to manipulate the DOMM.
8
setCount(count + 1);
9
};
10
​
11
console.log('counter function component');
12
if (count > 3) {
13
// make a runtime rendering error, assign the click event to something else
14
incrementCount = <h1>This assignment causes error!!!! :(</h1>;
15
}
16
​
17
return (
18
<div>
19
<p>You clicked {count} times</p>
20
<button onClick={incrementCount}>Click me</button>
21
</div>
22
);
23
}
Copied!

Error Boundary

1
class CounterErrorBoundary extends React.Component {
2
constructor(props) {
3
super(props);
4
this.state = { hasError: false };
5
}
6
​
7
componentDidCatch(error, errorInfo) {
8
console.log('error detected! we are setting state');
9
this.setState({ hasError: true });
10
}
11
​
12
render() {
13
if (this.state.hasError) {
14
console.log('rendering error');
15
// You can render any custom fallback UI
16
return <h1>Something went wrong inside counter!!</h1>;
17
}
18
​
19
// in this example this.props.children is Counter component used
20
// below in the App component
21
return this.props.children;
22
}
23
}
Copied!

App

1
export default function App() {
2
console.log('App');
3
return (
4
<div>
5
This is App.jsx
6
<CounterErrorBoundary>
7
<Counter />
8
</CounterErrorBoundary>
9
</div>
10
);
11
}
Copied!
See more about error boundaries in the docs: https://reactjs.org/docs/error-boundaries.html​
Last modified 2mo ago