Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Rejected promise in deferred data does not bubble up to the closest error boundary #11069

Closed
silvenon opened this issue Nov 29, 2023 · 10 comments · Fixed by #11071
Closed
Labels

Comments

@silvenon
Copy link

What version of React Router are you using?

6.20.0

Steps to Reproduce

import {
  createBrowserRouter,
  RouterProvider,
  useLoaderData,
  defer,
  Await,
} from "react-router-dom";
import { Suspense } from "react";

const router = createBrowserRouter([
  {
    path: "/",
    loader() {
      return defer({
        data: Promise.reject(null),
      });
    },
    Component() {
      const { data } = useLoaderData() as { data: Promise<null> };
      return (
        <Suspense>
          <Await resolve={data}>{() => <div>Whatever</div>}</Await>
        </Suspense>
      );
    },
    errorElement: <div>Oops, an error!</div>,
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

export default App;

Expected Behavior

Deferred data failed, so I expected to see the contents of errorElement, i.e. the error boundary.

If you do not provide an errorElement, the rejected value will bubble up to the nearest route-level errorElement and be accessible via the useRouteError hook.

errorElement in Await

Actual Behavior

Instead I don't see anything, and see the following stack trace in my browser console:

The above error occurred in the <AwaitErrorBoundary> component:

AwaitErrorBoundary@http://localhost:5173/node_modules/.vite/deps/react-router-dom.js:3916:10
Await@http://localhost:5173/node_modules/.vite/deps/react-router-dom.js:3900:12
Suspense
Component@http://localhost:5173/src/App.tsx:38:43
RenderedRoute@http://localhost:5173/node_modules/.vite/deps/react-router-dom.js:3511:11
RenderedRoute@http://localhost:5173/node_modules/.vite/deps/react-router-dom.js:3511:11
RenderErrorBoundary@http://localhost:5173/node_modules/.vite/deps/react-router-dom.js:3468:10
DataRoutes@http://localhost:5173/node_modules/.vite/deps/react-router-dom.js:4542:12
Router@http://localhost:5173/node_modules/.vite/deps/react-router-dom.js:3843:12
RouterProvider@http://localhost:5173/node_modules/.vite/deps/react-router-dom.js:4367:11
App

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
@silvenon silvenon added the bug label Nov 29, 2023
@brophdawg11
Copy link
Contributor

This looks like a small bug because you're throwing null as the error and we just check for truthiness of the error in the boundary. You can avoid this by throwing a non-falsy value but I'll get a fix prepared to handle other thrown falsy values properly here.

@silvenon
Copy link
Author

silvenon commented Nov 29, 2023

Oh, I see! Those are two separate issues then. Rejecting with a truthy value still results in a similar undesired console error message, but does indeed show the error boundary. ❤️

Should I create a separate issue for that?

@brophdawg11
Copy link
Contributor

That console error is logged by React when an error is thrown to the nearest error boundary. If you'd like to avoid it, you can specify an errorElement on the Await component to handle it directly:

<Await resolve={data} errorElement={<p>oops</p>}>

Otherwise, there is no choice but to throw it so it bubbles up the route hierarchy - so the log is unavoidable in that case.

@silvenon
Copy link
Author

Both React and React Router log the error.

componentDidCatch(error: any, errorInfo: any) {
console.error(
"React Router caught the following error during render",
error,
errorInfo
);
}

Indeed the error is gone if I add an errorElement to Await, but I want the error to bubble up to the route error boundary, but logging the errors ruins my test output because it look like something unexpected happened, while in fact I'm just testing the error boundary.

I wish there was a way to prevent automatically logging errors when there's an error boundary, so that I can control whether to log them or not.

Thanks for you help! I guess I have some more learning to do.

@brophdawg11
Copy link
Contributor

Sorry - the error in the description above is logged by React 😉 . React Router also logs the error afterwards - but at that point the console is already dirtied. Generally speaking, I don't think swallowing error logs is advisable since it allows things to go wrong without being noticed. This seems to be the stance of the React team as well: facebook/react#15069.

logging the errors ruins my test output

If this is only a test concern - can't you use a spy on console.error to avoid logging the output?

jest.spyOn(console, "warn").mockImplementation(() => {});

@silvenon
Copy link
Author

silvenon commented Dec 3, 2023

If this is only a test concern - can't you use a spy on console.error to avoid logging the output?

Good idea, thanks!

@silvenon
Copy link
Author

silvenon commented Dec 3, 2023

Generally speaking, I don't think swallowing error logs is advisable since it allows things to go wrong without being noticed.

Yeah, after several hours of thinking about this I started seeing it as a good thing.

@brophdawg11
Copy link
Contributor

This is resolved by #11071 and will be available in the next release

@brophdawg11 brophdawg11 added the awaiting release This issue have been fixed and will be released soon label Dec 4, 2023
Copy link
Contributor

github-actions bot commented Dec 5, 2023

🤖 Hello there,

We just published version 6.21.0-pre.0 which involves this issue. If you'd like to take it for a test run please try it out and let us know what you think!

Thanks!

Copy link
Contributor

🤖 Hello there,

We just published version 6.21.0 which involves this issue. If you'd like to take it for a test run please try it out and let us know what you think!

Thanks!

@brophdawg11 brophdawg11 removed the awaiting release This issue have been fixed and will be released soon label Dec 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants