This issue was discussed in #3627, but it's been marked and stale as locked so I'm opening another issue.
As discussed in #3627, create-react-app will always display an error overlay for errors in development mode, even when the error is caught via an error boundary. This confused me at first, and it's also confusing users of the routing library I maintain. This library throws a NotFoundError
when it can't match a URL segment, and uses a <NotFoundBoundary>
component to allow the user to render a 404 page.
<div className='App'>
<Sidebar />
<main>
<NotFoundBoundary render={() => <NotFoundPage />}>
{/**
<View /> throws a NotFoundError if they can't find a route any content for
the part of the URL they correspond to. They can be nested, so even if
this view doesn't throw, a child view might -- thus boundaries are 馃憣
**/}
<View />
</NotFoundBoundary>
</main>
</div>
I feel like the best approach would be to not show error overlays for caught errors (Dan mentioned it's on his todos). But just making it clearer that the error was caught would be a big improvement.
I'd like to bring this up again. Especially as ErrorBoundaries are increasing in use, having the error-overlay pop up when the error is handled is pretty disruptive. Would love for caught errors to not trigger the overlay.
I've been diving in a bit and it looks like "all" that would be needed is to somehow determine whether an error was handled by an ErrorBoundary (not sure whether React exposes that information) and update these to not handle errors that were passed to an ErrorBoundary: https://github.com/facebook/create-react-app/tree/master/packages/react-error-overlay/src/effects
What if the error overlay didn't take up the full screen and appeared as a intuitively dismissible modal instead?
This is the best balance IMO:
I think that would also be nice, but its presence is really annoying when working on error boundaries or if you're working on one part of the app but another part of the app has a failing network request but doesn't really matter because you're not working on that right now, etc.
An error boundary is a way to say: "this is handled" Having something jump out at you when you've handled something is annoying and unhelpful IMO.
I'm not convinced it'd be a DX win to see no overlay whatsoever for an unhandled error in your application. I guess this could become more annoying if you're leveraging error boundaries for "known" view states instead of unexpected errors.
I definitely do feel pain for network errors鈥攊n this case, the error overlay could remain dismissed if more errors continue to flow in:
I'm not convinced it'd be a DX win to see no overlay whatsoever for an unhandled error in your application.
I agree with you. I'm not talking about "unhandled errors" we're talking about handled errors. Errors handled by an error boundary. That's handling the error.
Personally, I consider an error boundary being triggered an unhandled error: your component tree crashed (notwithstanding experimental features). I can see how opinions would differ here, though.
How would you handle the case of an application that has a top-level (generic) error boundary that's used as a last resort to ask the user to refresh the application? You'd want to see the overlay in this case鈥攊t seems we'd want to make the distinction between intentional error boundaries and accidental ones.
edit: I'm going to try to reach out to Dan to learn about how they treat this case internally at FB.
intentional error boundaries and accidental ones.
I'd say including an error boundary at all is intentional. I think the developer will see that their error boundary was triggered and can investigate. I suppose it may be unfortunate that they would not get the overlay to help them investigate.
What if we do this... Add a class or ID to the iframe so it can be targeted with CSS to add display: none;
? That's as good as any opt-out I can think of. Thoughts?
Let me share some background on why it works this way.
Yes, error boundaries are a way to catch errors. However, error boundaries are a part of your UI. This means that, just like any part of UI, they might not be visible. Maybe they're inside a display: none
tree. Maybe they're behind something else due to the z-index
. Maybe the part that errored is below or above the viewport. Maybe it is in a portal (e.g. a tooltip). Maybe an error boundary wraps a component that currently has very little height and width, and is very easy to miss. As a result of all these plausible scenarios, you risk not noticing the error at all.
Next, I will claim that most errors are, in fact, going to be programming errors, and not intentional ones. People make mistakes all the time, and JavaScript is a dynamic language. There will be typos, null references, crashes, and so on. During the course of development you'll have a lot more of them than intentional throws. I think we should optimize the experience for catching bad errors early, even if it hurts some other cases.
Additionally, the distinction between "caught" and "uncaught" errors in this case doesn't have any substance. It would appear that even wrapping your whole app in one boundary would suddenly mark all errors as "caught". Since every app should have a boundary, and we'll likely add one by default into CRA and Next templates to encourage people to design them, there would be no "uncaught" errors in principle. So it is not a very meaningful distinction for rendering errors.
Due to these three points, I recommend against a blanket solution like "don't show dialog for caught errors". In practice, most of them should be "caught" so this is more or less equivalent to removing the error dialog altogether and hoping for the best.
I think it's fair to say that like in the original post, some errors are intentional. We don't have a very good mechanism for distinguishing them in React. We might eventually introduce one. But these are already shown in console, so it's also not like the dialog acts in a special way. It attempts to mirror what the console is doing.
I get that the dialog is obtrusive in these cases. As a compromise, I propose the following solution:
ReferenceError
or TypeError
, always show the dialog. No exemptions.This way, you're not going to miss important errors, but the dialog also doesn't distract you from seeing your own custom boundaries.
Thanks @gaearon! That all makes complete sense and I'm a fan of the proposed solution 馃憤
This would work fine for my use case as well. I think it's a solid compromise 馃憤
Most helpful comment
Let me share some background on why it works this way.
Yes, error boundaries are a way to catch errors. However, error boundaries are a part of your UI. This means that, just like any part of UI, they might not be visible. Maybe they're inside a
display: none
tree. Maybe they're behind something else due to thez-index
. Maybe the part that errored is below or above the viewport. Maybe it is in a portal (e.g. a tooltip). Maybe an error boundary wraps a component that currently has very little height and width, and is very easy to miss. As a result of all these plausible scenarios, you risk not noticing the error at all.Next, I will claim that most errors are, in fact, going to be programming errors, and not intentional ones. People make mistakes all the time, and JavaScript is a dynamic language. There will be typos, null references, crashes, and so on. During the course of development you'll have a lot more of them than intentional throws. I think we should optimize the experience for catching bad errors early, even if it hurts some other cases.
Additionally, the distinction between "caught" and "uncaught" errors in this case doesn't have any substance. It would appear that even wrapping your whole app in one boundary would suddenly mark all errors as "caught". Since every app should have a boundary, and we'll likely add one by default into CRA and Next templates to encourage people to design them, there would be no "uncaught" errors in principle. So it is not a very meaningful distinction for rendering errors.
Due to these three points, I recommend against a blanket solution like "don't show dialog for caught errors". In practice, most of them should be "caught" so this is more or less equivalent to removing the error dialog altogether and hoping for the best.
I think it's fair to say that like in the original post, some errors are intentional. We don't have a very good mechanism for distinguishing them in React. We might eventually introduce one. But these are already shown in console, so it's also not like the dialog acts in a special way. It attempts to mirror what the console is doing.
I get that the dialog is obtrusive in these cases. As a compromise, I propose the following solution:
ReferenceError
orTypeError
, always show the dialog. No exemptions.This way, you're not going to miss important errors, but the dialog also doesn't distract you from seeing your own custom boundaries.