Reputation: 3943
I'm not quite sure, if I fully understand the concept of React ErrorBoundary
.
I need to say, that I actually want to start using the ErrorBoundary, but I'm using it for the first time.
So I created an ErrorBoundary
component:
import React, { Component } from "react";
import * as Data from '../../backend/data';
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, stackTrace) {
this.setState({ hasError: true });
console.log(error, stackTrace);
// Send error to backend
Data.trackError(error, stackTrace.componentStack, this.props.component, this.props.location, this.props.guestLandingPage?.identifier_token, this.props.user?.id);
}
render() {
if (this.state.hasError) {
return this.props.fallbackUI;
}
return this.props.children;
}
}
export default ErrorBoundary;
Now I tried to using it in my app.container.js
(I will not copy the whole code of it, just the neccessary parts of it):
...
import NavBarComponent from './components/navbar.component';
import ErrorBoundary from './components/error/error.component';
import FallbackUI from './components/error/standardFallback.component';
...
class App extends Component {
...
render() {
const View = this.importView();
return (
<ErrorBoundary
location={"builder"}
component={"app.container.js"}
user={this.props.user}
fallbackUI={<FallbackUI />}
>
<Wrap>
<NavBarComponent
key={"navBarComponent"}
/>
...
</Wrap>
...
</ErrorBoundary>
)
}
}
Then I started to create manually an error. I added a variable in my navbar.component.js
which is not existing and lead to throw an error.
That works fine so far. The error is being send to the backend and my fallback UI component is displayed. So far, so good.
Now, however, I did not want to catch the error at the top level, but in the individual components, so that the app is still available and an error message is only displayed in individual components in case of an error.
Therefore, I have now moved the ErrorBoundary
component to navbar.component.js
(and deleted it from app.container.js
).
class NavBarComponent extends Component {
...
render() {
return (
<ErrorBoundary
location={"builder"}
component={"navbar.component.js"}
user={this.props.user}
fallbackUI={<FallbackUI />}
>
<Nav className="navbar navbar-expand-lg navbar-light">
...
</Nav>
</ErrorBoundary>
);
}
}
...expecting the same result, but showing my fallback UI component only where the navbar is displayed. But actually the result is, that the ErrorBoundary
is not being fired at all when moved to navbar.
Why? Is it not possible to add the ErrorBoundary
component to each component itself, so that only the component with the error will not be displayed and not the whole app?
PS: I was also wondering, why I could not use both getDerivedStateFromError
and componentDidCatch
method in my ErrorBoundary
component. When defined getDerivedStateFromError
method in ErrorBoundary
, the method componentDidCatch
was never called:
static getDerivedStateFromError(error) {
return { hasError: true };
}
...but as far as I can see, it works fine with just using componentDidCatch
.
Upvotes: 2
Views: 619
Reputation: 281764
Since the error occurs within navbar.component.js
, the ErrorBoundary
must be present somewhere in its parent hierarchy. Currently, you are using it as a child of navbar.component.js
Updating the ErrorBoundary usage to below should work as you expect it to
class App extends Component {
...
render() {
const View = this.importView();
return (
<Wrap>
<ErrorBoundary
location={"builder"}
component={"app.container.js"}
user={this.props.user}
fallbackUI={<FallbackUI />}
>
<NavBarComponent
key={"navBarComponent"}
/>
</ErrorBoundary>
...
</Wrap>
...
)
}
}
You could also export the component by wrapping it with ErrorBoundary so that you don't have to do this everywhere you render the component
export default ({location, user, ...props}) => {
return (
<ErrorBoundary
location={location}
component={"navbar.component.js"}
user={user}
fallbackUI={<FallbackUI />}
>
<NavBarComponent
key={"navBarComponent"}
{...props}
/>
</ErrorBoundary>
)
}
and use it like
class App extends Component {
...
render() {
const View = this.importView();
return (
<Wrap>
<NavBarComponent
location={"builder"}
user={this.props.user}
key={"navBarComponent"}
/>
...
</Wrap>
)
}
}
Upvotes: 3