React error boundary component processing

React error boundary component processing

This is the content of React 16. It is not the latest technology, but it is rarely discussed until I found it through the documentation. It is actually a very useful part. Let’s summarize it~

Uncaught JS errors in React can cause the entire application to crash and the entire component tree to be unmounted. This has been the case since React 16. But at the same time, React also introduced a new concept - error boundary.

Definition, what is

An error boundary is still a component that can catch (print or otherwise) handle JavaScript errors anywhere in its child component tree and render an alternative UI as needed.

Works similarly to try-catch, but error boundaries are only used for React components.

Only class components can become error boundary components. Error boundaries can only capture errors in subcomponents, not their own errors.

Error boundaries catch errors during rendering, in the lifecycle, and in constructors for the entire component tree. Without error boundary handling, the rendered child component tree will still collapse, which is obviously not what we want.

Let's take a look at an example to demonstrate how to use error boundaries step by step:

export default class ErrorTest extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div>
        <BugCounter></BugCounter>
        <span>my name is dan</span>
      </div>
    );
  }
}

// Bug error component class BugCounter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 0,
    };
  }
  click = () => {
    this.setState(({ counter }) => ({ counter: counter + 1 }));
  };
  render() {
    if (this.state.counter === 5) {
      throw new Error("crashed!");
    }
    return (
      <div>
        <h3 onClick={this.click}>{this.state.counter}</h3>
      </div>
    );
  }
}

The rendering result of the above code (ignoring styles):

Click the number 0 and it will increase gradually. But when the number is equal to 5 , the component will throw an Error :

This Error will cause the entire Demo to crash, and even the external <span>my name is dan</span> will not be displayed. At this time, no error boundary has been added.

In production mode, a white screen will appear and an error will be reported in the console:

getDerivedStateFromError & componentDidCatch

An error boundary is needed to handle this kind of crash. How to define an error boundary?

Define a component and implement static getDerivedStateFromError() or componentDidCatch() lifecycle method (you can implement both or choose one). This component will become an error boundary.

Regarding these two life cycle functions, you can view them through the link, which is summarized as follows:

componentDidCatch(error, info)

error is the error object thrown, and info contains the stack trace of the component that caused the error. Function is called during the commit phase. It is possible to perform side effects.

static getDerivedStateFromError(error)

Called after a child component throws an error, with the thrown error as argument. A value needs to be returned to update the state. This function is called during the rendering phase and no side effects are allowed. If you need to perform side effects after catching an error, you should do so in componentDidCatch .

Making an Error Boundary Component

You can use the combination method to add an error boundary component to wrap the component you want to use. This component requires these effects:

  • Capture subcomponent errors and record error status inside the component
  • Display alternative UI in error state and display subcomponents in normal state

Then it can be like this:

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so that the next rendering can display the degraded UI
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // You can also report error logs to the server logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // You can customize the downgraded UI and render return <h1>Something went wrong.</h1>;
    }

    return this.props.children; 
  }
}

The side effect after catching the error is customized, uploading to the server, or using state records and then displaying it on the page:

componentDidCatch(error, errorInfo) {
  // Catch errors in any components below and re-render with error message
  this.setState({
    error: error,
    errorInfo: errorInfo
  })
}

Capture Processing

Add all the code, wrap the problematic component with the error boundary component, and see the result:

import { Component } from "react";

export default class ErrorTest extends Component {
  render() {
    return (
      <div>
        <ErrorBoundary>
          <BugCounter></BugCounter>
        </ErrorBoundary>
        <span>my name is dan</span>
      </div>
    );
  }
}

// Bug error component class BugCounter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 0,
    };
  }
  click = () => {
    this.setState(({ counter }) => ({ counter: counter + 1 }));
  };
  render() {
    if (this.state.counter === 5) {
      throw new Error("crashed!");
    }
    return (
      <div>
        <h3 onClick={this.click}>{this.state.counter}</h3>
      </div>
    );
  }
}

// Error boundary processing component class ErrorBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so that the next rendering can display the degraded UI
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      // You can customize the downgraded UI and render return <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}

Throwing an exception still reports an error in development mode, but after using yarn build and then hanging it up through http-server , access the production page:

It can be seen that although the console error occurs due to throw error , the display of my name is dan is not affected. In other words, the subcomponent error inside the error boundary does not affect other external components and elements.

Scope

Error boundaries are used to handle errors in the subcomponent life cycle and rendering functions. For event handlers, they will not be triggered during rendering. try catch should be used for exceptions thrown by event handlers.

Error boundaries cannot catch errors in the following scenarios:

  • Event Handling
  • Asynchronous code
  • Server-side rendering
  • Errors thrown by the error boundary itself (not child components)

Regarding error boundaries, an official demo of React is worth trying:

https://codepen.io/gaearon/pen/wqvxGa?editors=0010

refer to:

https://zh-hans.reactjs.org/docs/error-boundaries.html

https://zh-hans.reactjs.org/docs/react-component.html

https://codepen.io/gaearon/pen/wqvxGa?editors=0010

This is the end of this article about the handling of React error boundary components. For more relevant React error boundary content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Encapsulate a simplest ErrorBoundary component to handle react exceptions
  • Implementation of Portals and Error Boundary Handling in React
  • Detailed explanation of exception handling in React 16
  • React workflow and Error Boundaries implementation process explanation

<<:  Use of Zabbix Api in Linux shell environment

>>:  How to solve the problem of MySQL query character set mismatch

Recommend

HTML CSS3 does not stretch the image display effect

1. Use the transform attribute to display the ima...

Detailed explanation of the installation process of Jenkins on CentOS 7

Install Jenkins via Yum 1. Installation # yum sou...

Three.js sample code for implementing dewdrop animation effect

Preface Hello everyone, this is the CSS wizard - ...

How does Vue3's dynamic components work?

Table of contents 1. Component Registration 1.1 G...

15 important variables you must know about MySQL performance tuning (summary)

Preface: MYSQL should be the most popular WEB bac...

Some notes on mysql self-join deduplication

Let me briefly explain the functional scenario: T...

Docker renames the image name and TAG operation

When using docker images, images with both REPOSI...

Example of how to implement underline effects using Css and JS

This article mainly describes two kinds of underl...

Some pitfalls of JavaScript deep copy

Preface When I went to an interview at a company ...

How to quickly query 10 million records in Mysql

Table of contents Normal paging query How to opti...