Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Use Error Boundaries for Better Error Handling in React 16

DZone's Guide to

How to Use Error Boundaries for Better Error Handling in React 16

React has gained a lot of popularity for making web devs lives a lot easier. Read on to get a great example of this with its error handling capabilities.

· Web Dev Zone
Free Resource

Get the senior executive’s handbook of important trends, tips, and strategies to compete and win in the digital economy.

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 has 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 to 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.

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>
    )
  }
}

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!

@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:

<script type="text/javascript">
    rg4js('apiKey', 'paste_your_api_key_here');
    rg4js('enableCrashReporting', true);
</script>

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.

Read this guide to learn everything you need to know about RPA, and how it can help you manage and automate your processes.

Topics:
web dev ,react ,error handling ,web application development

Published at DZone with permission of Sam Holt, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}