How to use error boundaries for better error handling in React 16
Posted Oct 13, 2017 | 5 min. (879 words)React recently announced their latest version release, React 16. Although a relatively light release feature-wise, React 16 completely overhauled their inner workings. This release sees marked improvements to the React 16 error handling process.
Today, I’m going to show you how React have made it much easier (and more reliable) to handle errors in React applications with the release of error boundaries.
The introduction of error boundaries
Firstly, I’ll take a look at the introduction of error boundaries, which are probably the most exciting new feature for us here at Raygun. They provide a consistent way to handle and deal with errors while minimizing the potential to bring down your entire application.
Below, I’ve added an example of an error boundary container to handle general application errors, display a generic user-friendly error message the user, a developer-friendly message to the engineering team (when serving locally), and automatically send the error and component stack to our Raygun account.
Declaration:
// errorBoundary.jsx
export class ErrorBoundaryAppContainer extends React.Component {
constructor(props) {
super(props);
}
state = {
currentError: null,
errorInfo: null,
};
componentDidCatch(error, info) {
this.setState({
currentError: error,
errorInfo: info
});
// Send error and error info to Raygun!
if(!!window.rg4js) {
rg4js('send', error);
rg4js('customTags', info);
}
}
render() {
if (!!this.state.currentError) {
return <ErrorPanel {...this.props} currentError={this.state.currentError} errorInfo={this.state.errorInfo} />;
}
return this.props.children;
}
}
ErrorBoundaryAppContainer.defaultProps = {
debugMode: false
};
Implementation:
// app.jsx
class App extends React.Component {
constructor(props) {
super(props);
}
// ...
render() {
return (
<div className="page-wrap">
<ErrorBoundaryAppContainer debugMode>
<Dashboard panels={this.state.currentStore.panels} handleStoreUpdate={this.handleStoreUpdate} />
</ErrorBoundaryAppContainer>
</div>
)
}
};
ReactDOM.render(
<App />,
document.getElementById('app')
);
The examples are on GitHub.
- Declaration
- Implementation
You can also now make custom messages for situations where more specific details might be required.
Declaration
// errorBoundary.jsx
export class DashboardPanelErrorBoundary extends React.Component {
constructor(props) {
super(props);
}
state = {
errorMessage: '',
hasError: false
}
componentDidCatch(error) {
this.setState({
hasError: true,
errorMessage: error.message
});
}
render() {
if(this.state.hasError) {
return(
<div className="dashboard__panel dashboard__panel--error">
<div className="panel-header">
<h3>{this.state.errorMessage}</h3>
</div>
<div className="panel-content">
<div className="sad-face">😞</div>
</div>
</div>
);
}
return this.props.children;
}
}
Declaration
// dashboard.jsx
export class Dashboard extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="dashboard">
<DashboardPanelErrorBoundary>
<AddDashboardPanel {...this.props} />
</DashboardPanelErrorBoundary>
{this.props.panels.map((panel) => ( <DashboardPanel {...panel}/> ))}
</div>
)
}
}
- Declaration
- Implementation
Here, you have a simplified example of some unexpected behavior in our application; there are no more panels to add to the dashboard for some reason. Instead of showing the add panel interface (which would just do nothing at this point) you can display to the user that you have run out of panels.
The introduction of portals
Secondly, another helpful new feature of React 16 is ‘portals’. Portals allow you to inject DOM nodes into a different DOM element to the root node. This allows us a little bit more flexibility for rendering components which just don’t belong in the root node. I’ve created an example of how you can build a quick and easy modal window using a Portal.
I’ve created an example of how you can build a quick and easy modal dialog window using a Portal, which you can view here on GitHub.
// modal.jsx
class ModalContainer extends React.Component {
constructor(props) {
super(props);
}
render () {
return ReactDOM.createPortal(
this.props.children,
document.getElementById('modal-container'),
);
}
}
export class Modal extends React.Component {
constructor(props) {
super(props);
}
state = {
open: false
}
render() {
return (
<ModalContainer>
<div className="modal-background"></div>
<div className="modal-content">
{this.props.children}
</div>
</ModalContainer>
);
}
}
Some other interesting tools I explored along the way are:
CodePen Projects
At this point in time, the Projects application is still in Beta but is working well and proving to be really helpful. They have made it straightforward to add external resources, the Babel/webpack/Sass processes all happen in the background so it’s great for building something quick and simple.
CSS Grid Layout
Modern browser support is looking pretty good, and it’s a powerful addition to the CSS spec. I took the chance to create a simple grid layout using minimal HTML and CSS. No more CSS classes a mile long, no more nasty gutter padding hacks, Sass loops or unpredictable floats!
// modal.jsx
@include mq-large-up() {
.dashboard {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 1rem 1rem;
}
.dashboard__panel {
margin: 0;
}
.dashboard__panel--span-2 {
grid-column: span 2;
}
.dashboard__panel--span-3 {
grid-column: span 3;
}
}
That’s it… Only a couple of modifier classes required and you’ve got yourself a responsive grid.
In conclusion, React 16 adds some very useful features to the framework, making it easier for web developers to adhere to best practices and build reusable and easily maintainable components.
See the full Codepen project here.
React.js error handling with Raygun
What about React.js error handling and exception tracking though? Raygun and React get on well – so well in fact that you don’t even need to do anything special to get started.
Include Raygun4JS in your site’s header and initialize it as you would any other Javascript application:
If you’re working with an ES6 transformation, remember to upload your source maps and Raygun will produce useful stack traces for you. You can check your source map validation with Raygun’s free JavaScript source map checker here.
Related articles
Six essential tools for monitoring your deployment tracking
How to handle errors in large-scale software projects