0

How do you wrap one or more routes in an error boundary component? I am using React version 16 and have tried wrapping two routes in error boundaries but am experiencing some unexpected behaviour.

I do not get any error messages at all - but one component will, sometimes, not mount.

When switching between two routes using the same child component (form), the parent component will not update or mount at all. The URL in the web browser location bar updates correctly though. (I am using the same child component for add/edit but with different props)

Is this an issue with ErrorBoundary? Do I need to instruct it somehow?

I have read the documentation on reactjs.org but cannot find any information regarding my issue. Am I missing how the ErrorBoundary is supposed to work?

Happy if you can lead me in the right direction for solving this issue.

See simple code example below.

export const history = createHistory();
const AppRouter = () => (
<Router history={history}>
  <div>
    <PrivateRoute component={Header} />
    <Switch>
      <PrivateRoute path="/dashboard" component={DashboardPage} />

      <ErrorBoundary key="eb01">
        <PrivateRoute path="/category/edit_category/:id" component={EditCategoryPage} exact={true} />
      </ErrorBoundary>

      <ErrorBoundary key="eb02">
        <PrivateRoute path="/create_category" component={AddCategoryPage} exact={true} />
      </ErrorBoundary>
    </Switch>
  </div>
</Router>
);

The Error boundary component

import React from 'react';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { error: null, errorInfo: null };

    const { history } = props;

    history.listen((location, action) => {
      if (this.state.hasError) {
        this.setState({
          hasError: false,
        });
      }
    });
  }

  componentDidCatch(error, errorInfo) {
    // Catch errors in any components below and re-render with error message
    this.setState({
      error: error,
      errorInfo: errorInfo
    })
    // You can also log error messages to an error reporting service here
  }

  render() {
    if (this.state.errorInfo) {
      // Error path
      return (
        <div>
          <h2>Something went wrong</h2>
          <details style={{ whiteSpace: 'pre-wrap' }}>
            {this.state.error && this.state.error.toString()}
            <br />
            {this.state.errorInfo.componentStack}
          </details>
        </div>
      );
    }
    // Normally, just render children
    return this.props.children;
  }
}
export default ErrorBoundary;

Update


I also tried to wrap the component -not the route- in the ErrorBoundary component.

<PrivateRoute path="/category/edit_category/:id" 
  render={() => (
    <ErrorBoundary>
      <EditCategoryPage/>
    </ErrorBoundary>
  )}
exact={true}/>

I now receive an error (the components are correctly imported - I can use them elsewhere in the same file)

Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Kermit
  • 2,865
  • 3
  • 30
  • 53
  • I suspect the ErrorBoundary component only returns the route, but does not trigger all events to render the component for the route. So I tried to render the component in the route. But then I get another message. The components have been imported. See update above. – Kermit Oct 28 '18 at 16:58

1 Answers1

0

I had wrapped the React-Router in my own component. That is why my code did not work! doh!

When adding ErrorBoundary in the right place (my own component) everything worked as expected. :)

export const PrivateRoute = ({
  isAuthenticated, 
  component: Component,
  useErrorBoundary, 
  ...rest
}) => (
  <Route {...rest} component = {(props) => (
    isAuthenticated ? (
      (useErrorBoundary) ?
        <div>
          <ErrorBoundary>
            <Component {...props} /> 
          </ErrorBoundary>
        </div>
      :
        <div>
          <Component {...props} /> 
        </div>
    ) : (
      <Redirect to="/" /> //redirect if not auth
    )
  )
  }/>
);
Kermit
  • 2,865
  • 3
  • 30
  • 53
  • 2
    You should always use Error Boundaries, why making it optional? – Faheem Nov 12 '18 at 07:16
  • I was thinking it would be unnecessary to wrap static components - if I should ever use one in a route. But a better approach would maybe be to always use Error Boundary since that scenario is more of an exception? :) – Kermit Nov 12 '18 at 17:47