React shipped a major version (v16.0) this week. Because the project is developed in the open, the community has been able to track the progress of this release, get a feel for what’s on the horizon, and even shape what lands in it. Naturally, we’ve been eagerly anticipating the overhaul of error handling.
Here we’ll summarise what’s new, dive into error handling and show you how to make the most of the new features by hooking them up to Bugsnag.
From the outside: in short, not a huge amount. However, the internals have had a complete rewrite – a project known as “Fiber”, which has been underway for over a year.
Because of this huge internal changeset, the maintainers focused largely on compatibility with existing apps – wisely enabling them to leverage the huge ecosystem of working React apps in the wild as a catalogue of real-life test cases. Luckily for you, some ahead-of-the-curve teams tried out the release candidates and helped to iron out the creases. 😉
As part of the rewrite many private/internal APIs have changed or been removed, so if you were monkeypatching or fiddling with anything you shouldn’t have, you will probably need to update that.
The main feature additions are:
You can read all about the custom DOM attributes and #render() return types on the React blog – they’re nice, but we’re much more interested in error handling (surprised, much?).
Handling errors in React has been a frustrating endeavour. There’s been no consistent and failsafe way to catch and deal with errors, until now! The Fiber rewrite laid the groundwork for better error handling, starting with anew feature called Error Boundaries.
An error boundary is a React component with a #componentDidCatch(err, info) method. Any errors occurring in a component tree get reported up to the nearest error boundary’s #componentDidCatch function, giving your app the chance to:
Additionally, unhandled errors (those not caught by an error boundary) will cause the entire tree to be unmounted. Quite a drastic measure indeed, but considering the alternative of attempting to continue with the app in some undefined state…that’s what got us into this mess in the first place!
The upshot is that you should use error boundaries in your app so that when something goes wrong, you provide your users with a sensible UI, and yourselves with a detailed report of what happened.
We’d find it hard to disagree with this advice from the React team when they introduced Error Boundaries to the world…
~We … encourage you to use JS error reporting services … so that you can learn about unhandled exceptions as they happen in production, and fix them.
initialize bugsnag ASAP ###// initialize bugsnag ASAP, before other imports
import bugsnag from 'bugsnag-js'
const bugsnagClient = bugsnag('API_KEY')
import ReactDOM from 'react-dom'
import React from 'react'
import createPlugin from 'bugsnag-react'
###// wrap your entire app tree in the ErrorBoundary provided
const ErrorBoundary = bugsnagClient.use(createPlugin(React))
Any component lifecycle errors within the #<ErrorBoundary /> will be caught and handled by the #componentDidCatch() method. It’ll be reported to your dashboard like so:
If you were wondering why we wrapped the #<YourApp/> component rather than having the top-level component become an error boundary, note that an error boundary cannot handle its own errors, only those occurring within its subtree.
To explore this in more detail, check out our example project.
So hopefully you’re as excited as we are about finally being able to handle errors gracefully in React. We wish you a smooth and speedy upgrade to v16.0 and hope to see you sending some high quality reports to your dashboard in the near future! 🎉
Editor’s Note: This post was updated on December 11, 2017, for accuracy and comprehensiveness.