Author avatar

Pavneet Singh

Render Sub-component Error in React.js using Error Boundaries

Pavneet Singh

  • Aug 27, 2020
  • 6 Min read
  • 96 Views
  • Aug 27, 2020
  • 6 Min read
  • 96 Views
Web Development
Front End Web Development
Client-side Framework
React

Introduction

React components are often composed of multiple/nested subcomponents to enhance code quality. Breaking a larger component into different subcomponents is a great approach to achieve a clean and reusable structure, but sometimes this can lead to some crashes, due to problematic JavaScript code, invalid API usage, inconsistent flow, etc. These small, unexpected inconsistencies can crash the whole app, which is the least expected behavior by a user from any app. To handle these errors gracefully, React 16 introduced error boundaries components.

Error boundaries provide a convenient way to log errors while displaying a fallback UI to inform the users about the possible issue. This guide will cover the implementation of error boundaries to handle errors in the React UI hierarchy with pro tips.

Creating Error Boundary Component

Error boundaries are normal React components that act as a wrapper to catch the errors from the child components. A component can simply be converted into an error boundary component by defining either static getDerivedStateFromError(error) or componentDidCatch(error, errorInfo):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import React, { Component } from 'react';

export default class ErrorBoundary extends Component {

    state = { hasError: false };

    static getDerivedStateFromError(error) {
        // Update state to show the fallback UI during the next render phase
        return { hasError: true };
    }

    componentDidCatch(error, info) {
        // logging the error details
        console.log(`Cause: ${error}.\nStackTrace: ${info.componentStack}`);
    }

    render() {
        if (this.state.hasError) {
            // Return the fallback UI
            return <h3 style={{ 'text-align': 'center' }}>Unfortunately, something went wrong.</h3>;
        }

        return this.props.children;
    }
}
JSX

The difference between getDerivedStateFromError and componentDidCatch methods are based on:

LifeCycle

The getDerivedStateFromError is called during the render phase to update the state so that the fallback UI can be rendered as per the updated hasError value from the state object. On the other side, componentDidCatch is called during the commit phase that occurs after the render phase, so the ideal place to update the state is getDerivedStateFromError method.

Parameter

As you may have observed, componentDidCatch provides an additional info object that can be used to fetch the error stack-trace for logging purposes.

UseCase

Since the getDerivedStateFromError is called during the render method, and the rendering phase is often slower than the commit phase, it's recommended to use componentDidCatch for error details processing and logging tasks.

Error Boundary implementation

Once you have created an error boundary component, the next step is to simply wrap the component hierarchy inside the error boundary component:

1
2
3
4
5
6
7
// index.js
ReactDOM.render(
  <ErrorBoundary>
    <App />
  </ErrorBoundary>,
  document.getElementById('root')
);
JSX

The ErrorBoundary component wraps the App component and will catch any possible errors from the App or its subcomponents. The App component has been malformed intentionally to produce an error by invoking toLowerCase function on an undefined value:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default class App extends Component {
  state = {
    items: ["Banana", "Mango"],
  };

  render() {
    // error: because of invalid index 3, items[3] will return an undefined value
    // invoking toLowerCase on undefined value will produce an error
    const wrongItem = this.state.items[3].toLowerCase();

    return (
      <div className="container">
        <p>{'Hello World!'}</p>
      </div>
    );
  }
}
JSX

The App component will produce an error during the execution of the render function. The error will be caught by the ErrorBoundary component, and it will display the fallback error UI.

Note: React will display the stack-trace automatically in development mode, but this information won't be displayed in the production app. To view the fallback error UI, remove the error detail screen in development mode by simply pressing escape or clicking on the close (X) icon.

Error Boundaries Versus Try/Catch

The sole purpose of error boundaries is to handle the error during the execution of any lifecycle or render function of any nested subcomponent. Error boundaries do not handle errors from event-handlers, asynchronous code (Promise, fetch, etc.), and SSR (server-side rendering). Instead, a try-catch block should be used to handle errors in event-handlers or in any asynchronous task (e.g. Promises, setInterval, requestAnimationFrame, etc.). The major differences between error boundaries and try-catch are:

Rendering Error

Use error boundaries to handle error occurred during the creation/updation of any component in the hierarchy, because try-catch does not handle errors of subcomponents:

1
2
3
4
5
6
7
// inside the render function of a component
try{
    // no error will be captured by the catch block during creation/updation of ChildComponent
    return <ChildComponent />
}catch(e){
    console.log('error', e);  
}
JSX

Runtime Errors

Try-catch should be used to handle any potential issues that can occur due to invalid input/data, connection issues or bad server response, etc.

1
2
3
4
5
try{
    var response = getBooksFromStoreAPI();
}catch(e){
    console.log('error', e);
}
JSX

The getBooksFromStoreAPI() may throw an error because of invalid response or bad connection, which will be handled by the try-catch block.

Tips

  • UI can be divided into sections and use different error boundary components for each section to keep most of the app running smoothly.
  • Manage a boolean flag in state to display the fallback error UI. Additionally, state can store the error message details that can be used to inform users about the issue.

Conclusion

Error boundary is a great feature to handle errors gracefully in the component hierarchy. This guide has explained the necessary details to implement error boundaries in React with best practices. Make sure to use error boundaries for a smooth user experience. Happy coding!

0