2

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.

1 Answer 1

3

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>
        )
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. Yes, you are right. So I need to wrap each component in the parent component with the ErrorBoundary. As I said, I did not fully understand the concept, but now it becomes more clear. Many thanks!
Whichever component you need to provide the error boundary for will need to be wrapped by ErrorBounndaary. You can export them with a wrapped ErrorBoundary as I showed in my updated answer too

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.