DEV Community

Cover image for Yet another React Error Boundaries explanation
Peter Perlepes
Peter Perlepes

Posted on

Yet another React Error Boundaries explanation

This article is a kind of warm-up for the part 2 on how we can handle React Error Boundaries for better sync and async error handling using MobX.

This time...

There comes this time when you have to cater for your users and not let them be the real testers of your application.

That means making sure that the experience you are building is ready to handle the unexpected. The unexpected for us software engineers/developers working on the web is most of the times

  • some network request error
  • an unreachable resource or
  • just a human mistake due to insufficient test coverage

In any of these cases we don't want our users to either see a blank screen or end up in an unresponsive state; this will result in one of the worst things in experience design, confusion.

React to the rescue

To combat some of these cases, React v.16 and above has us covered with the componentDidCatch(error, info) lifecycle method. Every Component implementing this method becomes what is called an Error Boundary. In my understanding, a wrapper Component that catches unhandled errors/exceptions that bubble up from its children.
We won't get into too much detail on how this works and luckily for everyone using React, the core team has us covered in the Error Boundary documentation.

This though has created a bit of confusion around what errors can be handled by this component.
Is it an all around handler for Application-level errors ?
Is it only for caught exceptions ?
Does it only applies on React Component implementation ?

These and more questions by the community have raised some issues such as

componentDidCatch is not getting called when there is an error in promise #11334

As per the new react 16 release doc it says

"React 16 prints all errors that occurred during rendering to the console in development, even if the application accidentally swallows them."

I have a Parent component and a Child component. I have triggered an error in then block of promise. But it will call catch method of the promise, componentDidCatch of parent is not getting called. I am not sure whether this the expected behaviour.

Here is the jsfiddle https://jsfiddle.net/john1jan/Luktwrdm/14/

Fiddling around with it

What I can infer (and is most probably what the real purpose of this implementation is about) is that the Error Boundaries are made to handle exactly errors that technically , as Dan Abramov states, happen inside any React lifecycle hook. That means code executed synchronously in these methods. No Promise rejections/exceptions, no callback errors, nor any asynchronous code as mentioned in the documentation.

For a simple example you can check in this fiddle that the fetch error gets thrown but the Error Boundary componentDidCatchMethod never gets called. I am reminding you that this is not technically code that runs in the React lifecycle methods, so it is not handled by the Error Boundary.

On the contrary if you enable
this.setState(() => { throw err });
you will see that this now is getting handled by the Parent successfully. This seemed kind of non-intuitive and smelly to me but it seems to work as stated at https://github.com/facebook/react/issues/13523.
we need better error handling

Next steps

In the event that you are trying to build a larger application than this fiddle, this can get pretty messy, pretty quickly. Also you probably want to be in more control of how you handle each type of error and trust me you do not want to fatten up any Error Boundary Component with business logic and cross-cutting concerns.
In our case I will be showing you in the next part how we used MobX to set up an initial sketch, along with some helpers, for our component sync and async error handling logic.

P.S. If you haven't tried out MobX for state management, believe me you might be missing out on some state management pain alleviation.

Cover Image by Aamir Mohd Khan from Pixabay

Top comments (0)