How do I set up custom error handling with React?

Since version 16, React has shipped with a nice error handling mechanism for components, called error boundaries. These allow you to catch errors from child components and prevent them from propagating up the tree. Conceptually, this works like try-catch, but for the component tree instead of the call stack.

While this is a nice mechanism for components, if you want to set up a global, all-catching error handler, this mechanism is not enough. We will describe error boundaries below, and see what needs to be done in order to actually catch all errors that can be generated in your app.

Error Boundaries

You define an error boundary by defining the componentDidCatch(error, info) method on your component. When this is defined, the error will not propagate up to the parent component.

class MyErrorBoundary extends React.Component {   
    [...]
    componentDidCatch(error, info) {
        console.error(error);
    }
}

This will not catch all errors!

Error boundaries only apply to errors that happen during rendering. So errors originating anywhere else will not trigger this mechanism. This includes errors in event handlers, and errors in async calls (e.g. setTimeout(...) and similar).

If you want to apply a global error handler in your React app, you either have to wrap everything in a try-catch, or you can assign an error handler to the window object:

window.onerror = function(msg, src, lineno, colno, error) { /*your code*/ }

Be aware that what arguments are actually passed here varies by browser.

How do I log all errors globally?

If you want to log the errors that occur client side, and persist the errors to a server, you can do this by simply dropping in the catch.js script.

<script src="//cdn.catchjs.com/catch.js"></script>

This will automatically set up a global error handler in the browser, and catch all errors that reach it. These will then be logged to your CatchJS account, along with the telemetry needed to reproduce them. This part is framework agnostic, so it needs no set up from you.

If you also want to catch errors in your components, and log them to your CatchJS log, you can do so by defining componentDidCatch(...) and passing the error object onto console.error(...), as shown in the example above. CatchJS automatically instruments the console.error method, such that when an error object is passed to it, it will be persisted to the CatchJS error log, along with relevant telemetry.