I’m currently following along with the React JS documentation and I’ve encountered an issue with the error boundaries not working as expected. I’ve tried replicating the example shown in the CodePen provided by the docs, and a few other simple examples I've found on the internet, however it is not working the same for me as it is in the demo and I’m struggling to understand why.
The exact issue is that the error is being thrown twice because the BuggyCounter component gets rendered an extra time. I do not understand why the component is rending a second time.
Please have a look at this minimal example.
import React, { Component } from 'react';
function App() {
return (
<ErrorHandler>
<BuggyCounter />
</ErrorHandler>
);
}
class ErrorHandler extends Component {
constructor(props) {
super(props);
this.state = {
error: false,
errorInfo: null
}
}
componentDidCatch(error, errorInfo) {
this.setState({ error, errorInfo });
}
render() {
console.log('rendering ErrorHandler. ' + (this.state.error ? "error" : "no error"));
if(this.state.error) {
return <p>Error</p>
}
return this.props.children;
}
}
class BuggyCounter extends Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
}
handleClick = () => {
this.setState(({ counter }) => ({
counter: counter + 1
}));
};
render() {
console.log('rendering BuggyCounter. count: ' + this.state.counter);
if (this.state.counter === 5) {
throw new Error('I crashed!');
}
return <h1 onClick={this.handleClick}>{this.state.counter}</h1>
}
}
export default App;
The BuggyCounter component is being replaced with the <p>
tag which renders “Error” (which is the desired effect), but only for a moment. Immediately after that, the default error page is being shown, defeating the purpose of Error Boundaries.
Here is my console:
I would appreciate any information you could provide on this topic.
Temporary resolution:
It's not an answer to my question, but one way to prevent the redundant render is to throw the error from componentDidUpdate
instead of render
.
render() {
console.log('rendering BuggyCounter. count: ' + this.state.counter);
return <h1 onClick={this.handleClick}>{this.state.counter}</h1>
}
componentDidUpdate() {
if(this.state.counter === 5)
throw new Error('I crashed');
}
Error
` (on line 5 of BuggyCounter.render) would be the fallback UI. Is this not correct? – Anthony Yershov Feb 03 '20 at 20:10