3

We are trying to use react-error-boundary with react-router (v6) but seems like we need to wrap every route element with an error boundary as shown below

import { ErrorBoundary } from "react-error-boundary";

export const AppRoutes = createBrowserRouter([
{
   path: "/",
   element: <ErrorBoundary FallbackComponent={GlobalError}><Login /></ErrorBoundary>
},
{
  path: "login",
  element: <ErrorBoundary FallbackComponent={GlobalError}><Login /></ErrorBoundary>,
},
{
  path: "trans",
  element: <ErrorBoundary FallbackComponent={GlobalError}><Trans /></ErrorBoundary>
),
{
  path: "*",
  element: <ErrorBoundary FallbackComponent={GlobalError}><RouteNotFound /></ErrorBoundary>
}]);

Do we have a simpler way to do this like below? Any configuration flag in react-router to bubble up the error

import { ErrorBoundary } from "react-error-boundary";

<ErrorBoundary FallbackComponent={GlobalError}>
  <Header />
    <RouterProvider router={AppRoutes} />
  <Footer />
</ErrorBoundary>

Below is the screenshot of the error we get when we wrap the RouterProvider inside the Error Boundary

enter image description here

Below is a sample code for the Trans component to throw an error.

export function Trans() {
  const [error, setError] = useState(null);

  if (error) {
    throw error;
  }

  useEffect(() => {
    setTimeout(() => setError("This is error"), 2000);
   }, []);

  return <p>This is Trans</p>;
} 
user3205479
  • 1,443
  • 1
  • 17
  • 41

1 Answers1

4

The code snippets should work, but if you are wanting to make the code more DRY then instead of wrapping each route individually you can create a layout route that renders an Outlet component wrapped by the ErrorBoundary component.

Example:

import { createBrowserRouter, Outlet } from 'react-router-dom';
import { ErrorBoundary } from "react-error-boundary";

const ErrorBoundaryLayout = () => (
  <ErrorBoundary FallbackComponent={GlobalError}>
    <Outlet />
  </ErrorBoundary>
);

export const AppRoutes = createBrowserRouter([
  {
    element: <ErrorBoundaryLayout />,
    children: [
      {
        path: "/",
        element: <Login />,
      },
      {
        path: "login",
        element: <Login />,
      },
      {
        path: "trans",
        element: <Trans />,
      },
      {
        path: "*",
        element: <RouteNotFound />,
      },
    ],
  },
]);

You should note this for React Error Boundaries:

Note

Error boundaries do not catch errors for:

  • Event handlers (learn more)
  • Asynchronous code (e.g. setTimeout or requestAnimationFrame callbacks)
  • Server side rendering
  • Errors thrown in the error boundary itself (rather than its children)

In your Trans component example you are using a setTimeout to set some error state. I can only guess that maybe the thought process here is that some errors are considered "unrecoverable" so the error boundary kicks in and handles it, otherwise errors occurring in the points above are considered "recoverable" and your component code should be coded to potentially handle the scenarios of asynchronous issues like failed fetch requests, etc.

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • I like the approach of writing outlet we will use but could you please see the updated question with error image, we do get message stating to include error element or is it because of development build? – user3205479 Oct 10 '22 at 18:53
  • 2
    @user3205479 I'm working on a demo now. Reading up on this `react-error-boundary` package to see why it may be working different than I'd expect. – Drew Reese Oct 10 '22 at 18:55
  • Thank you so much! I guess it's the react-router after reaching the top it's showing the default error layout and not bubbling up to the parent component that has router – user3205479 Oct 10 '22 at 18:56
  • 1
    @user3205479 It seems the error boundary fallback is only rendered when the error occurs when mounting the component. See this [codesandbox](https://codesandbox.io/s/using-react-error-boundary-with-react-router-2zz91s?file=/src/App.js:1429-1502) where I tried several methods and the only way to trigger the ErrorBoundary is when mounting/initially rendering the component. Any errors thrown after just display the normal runtime screen with uncaught error. – Drew Reese Oct 10 '22 at 19:24
  • @user3205479 It's been a long time since I've used error boundaries and I do recall them having "odd" behavior. It's better to have your components catch potential errors/Promise rejections they might be expecting. – Drew Reese Oct 10 '22 at 19:24