I'm learning how to use componentDidCatch()
. It looks straight forward. It works, but to still show the complete error stack on view.
In separate files:
import React, { Component } from 'react'
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = {
hasError: false
}
}
componentDidCatch(error, info) {
console.log("Catching an error") // this is never logged
this.setState(state => ({...state, hasError: true }))
}
render() {
if (this.state.hasError) { return <div>Sorry, an error occurred</div> }
return this.props.children
}
}
export default ErrorBoundary
...
import React, { Component } from 'react'
class Foo extends Component {
render() {
return this.props.a.b; // So this should cause the error
}
}
export default Foo
...
import React, { Component } from 'react'
// Imported Foo and ErrorBoundary
class Home extends Component {
render() {
return <ErrorBoundary><Foo /></ErrorBoundary>
}
}
export default Home
On page refresh, I see Sorry, an error occurred
for, literally, a second then the full error stack displaying to the user. Is this an issue with Create React App? I'm using React 16.
Answers
The behavior you are describing suggests that the error boundary is catching the error initially, but then something is causing the error boundary to re-render or the error stack trace to be displayed by React's development overlay, which is a feature in Create React App during development.
To ensure that the error boundary consistently handles the error and to avoid the development overlay from showing up, you can do the following:
-
Disable the Error Overlay in Development: Create React App provides an overlay that shows the error stack trace in development mode. This is useful for debugging but can be disabled if it interferes with your error boundary testing.
-
Ensure Proper State Management: Make sure your error boundary's state is updated correctly and that it doesn't get reset by any other logic in your application.
Here's an updated version of your code with these considerations in mind:
ErrorBoundary.js
import React, { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
error: null,
errorInfo: null
};
}
componentDidCatch(error, errorInfo) {
console.log("Catching an error", error, errorInfo);
this.setState({
hasError: true,
error: error,
errorInfo: errorInfo
});
}
render() {
if (this.state.hasError) {
return (
<div>
<h2>Sorry, an error occurred</h2>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}
<br />
{this.state.errorInfo.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
Foo.js
import React, { Component } from 'react';
class Foo extends Component {
render() {
return this.props.a.b; // This should cause the error
}
}
export default Foo;
Home.js
import React, { Component } from 'react';
import ErrorBoundary from './ErrorBoundary';
import Foo from './Foo';
class Home extends Component {
render() {
return (
<ErrorBoundary>
<Foo />
</ErrorBoundary>
);
}
}
export default Home;
Disabling Error Overlay in Create React App
To disable the error overlay in Create React App, you can set an environment variable:
-
Create a
.env
file in the root of your project (if it doesn't already exist). -
Add the following line to the
.env
file:FAST_REFRESH=false
This will disable the fast refresh feature, which includes the error overlay.
Summary
- The
componentDidCatch
method now also logs the error and component stack to the state, so they can be displayed in the render method if an error occurs. - The error information is shown in a
<details>
tag, which provides a collapsible section to show the complete error stack trace. - Disabled the error overlay in Create React App by setting
FAST_REFRESH=false
in the.env
file.
By making these changes, you should see the error boundary consistently handling errors, and the full error stack trace will be displayed in the view when an error occurs.