dns_nx
dns_nx

Reputation: 3943

React.js - ErrorBoundary

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

Answers (1)

Shubham Khatri
Shubham Khatri

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

Related Questions