Encapsulate a simplest errorboundary component to handle react exceptions;

Time:2021-6-12

preface

Starting from react 16, the concept of error boundaries is introduced, which can capture the errors generated in its sub components, record the error log, display the degraded content, and specify the detailsOfficial website address。 ?

Alt

The error boundary can avoid the situation that a component error causes the whole page white screen to be unusable. The standby UI is presented in an elegant and degraded way. The error boundary can capture errors during rendering, in the lifecycle and in the constructor of the whole component tree. Since react 16, any error not caught by the error boundary will cause the entire react component tree to be unloaded


The meaning of errorboundary

  • Some UI crash, not the whole webapp crash

When browsing the page, the user experience will be very poor due to the back-end return exception or some error checking of the front-end. Think about it, you are taking your wife, sitting on the train, eating hot pot and singing,All of a sudden, he was robbed by muggersIn some scenarios, such as setting the amount of money or viewing key pages, the experience will be very bad. For example, if you recharge the game by 500, the result will be displayed due to the interfaceNaNHowever, I believe you are familiar with JS exception capture,try-catchA package of business code is over. However, for exception capture in components, you need to use the functions provided by reactError BoundaryError boundary feature, usingcomponentDidCatchHook to capture the page exception, so that the exception will not spread to the whole page, effectively prevent the page from white screen.


How to realize the official website

If any one (or two) of the two life cycle methods static getderivedstatefromerror() or componentdidcatch() is defined in a class component, it becomes an error boundary. When an error is thrown, use static getderivedstatefromerror() to render the standby UI, and use componentdidcatch() to print the error message

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

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

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

  render() {
    if (this.state.hasError) {
      //You can customize the degraded UI and render it
      return Something went wrong.;
    }

    return this.props.children;
  }
}

Then you can use it as a regular component:

Error bounds work like JavaScript doescatch {}The difference is that the error boundary is only forReactComponents. onlyclassComponent can be an error boundary component. In most cases, you only need to declare the error boundary component once, and use it throughout the application. When using it, the error or error of the wrapped component will occurthrow new Error()The exception thrown can be caught by the error boundary component, and the bottom UI is displayed


Encapsulating a configurable errorboundary

After understanding the method of implementing error boundary component on the official website, we can encapsulate oneErrorBoundaryComponents, to build a useful wheel, rather than directly write deadreturn Something went wrongI learnedreact-reduxAfter the principle, we know that it can be wrapped with higher-order componentsreactComponent, willstoreIn the same way, we can also use high-order component wrapping to make it a react component that can catch errors

one ️⃣ Create a configurable errorboundary class component

Compared with the official websiteErrorBoundary, we can report the log and display itUIDynamic configuration is implemented by accepting parameters. For the incomingUIWe can set thereactComponent or aReact ElementWe can also pass in parameters through components, so that we can get specific error information in the bottom UI

  • Componentdidcatch(): hook function for error log processing
  • Static getderivedstatefromerror(): it takes the error thrown as a parameter and returns a value to update the state
class ErrorBoundary extends React.Component {
  state = { error: false };
  static getDerivedStateFromError(error) {
    return { error };
  }
  componentDidCatch(error, errorInfo) {
    if (this.props.onError) {
      //The report log is executed through the function injected by the parent component
      this.props.onError(error, errorInfo.componentStack);
    }
  }
  render() {
    const { fallback, FallbackComponent } = this.props;
    const { error } = this.state;
    if (error) {
      const fallbackProps = { error };
      //Judge whether it is react element
      if (React.isValidElement(fallback)) {
        return fallback;
      }
      //Component input
      if (FallbackComponent) {
        return ;
      }
      Throw new error ("the errorboundary component needs to be passed into the bottom UI");
    }
    return this.props.children;
  }
}

So you can get the bottom of itUIDisplay andError logDynamic acquisition makes components more flexible, but there is another problem. Sometimes, the server suddenly 503 or 502, and the front end can’t get a response. At this time, a component reports an error, but it will return to normal after a while. A better way is for the user to click on itErrorBoundaryA method in the encapsulated component can be used to reload the faulty component without redrawing the page. At this time, a method should be exposed in the component that needs to be disclosed for referenceErrorBoundaryDeal with it

image-1

  1. Add a method to the errorboundary to detect whether there is an injection reset method. If there is a reset method, it will execute and reset the error in the state to false
resetErrorBoundary = () => {
  if (this.props.onReset) this.props.onReset();
  this.setState({ error: false });
};
  1. Add function component type in render to render. Reset method and error information can be passed to the current component as parameters for processing
render() {
    const { fallback, FallbackComponent, fallbackRender } = this.props;
    const { error } = this.state;
    if (error) {
      const fallbackProps = {
        error,
        resetErrorBoundary: this.resetErrorBoundary,
      };
      ...
      if (typeof fallbackRender === "function")return fallbackRender(fallbackProps);
      ...
    }
    return this.props.children;
  }

2. Return the errorboundary through a higher-order function

import React from "react";
import DefaultErrorBoundary from "./core";
const catchreacterror = (Boundary = DefaultErrorBoundary) => InnerComponent => {
  return props => (
    
      
    
  );
};

Use & test

Through a click auto increment demo, when the number reaches a certain value, an exception is thrown. Here, the class component and the function component are tested as the component that initiates the exception

  • The component that initiated the exception
//Function component
const fnCount1 = ({ count }) => {
  if (count == 3) throw new Error("count is three");
  return {count};
};
//Class component
class fnCount2 extends React.Component {
  render() {
    const { count } = this.props;
    if (count == 2) throw new Error("count is two");
    return {count};
  }
}
  • Function components that handle error exceptions
const errorbackfn = ({ error: { message }, resetErrorBoundary }) => (
  
    Error 
    {message}
    Try again
  
);
  • A common component that handles error exceptions
Const errorbackcom = () = > error, cannot be undone;
  • Test components
//Package the component that initiated the exception, and return a high-level component that can handle error editing
const SafeCount1 = catchreacterror()(fnCount1);
const SafeCount2 = catchreacterror()(fnCount2);

//Test main components
const App = () => {
  const [count, setCount] = useState(0);
  Const listenerror = (Arg, info) = > console.log ("error: + arg.message, info))// Callback on error
  const onReset = () => setCount(0); // Callback when clicking reset
  return (
    
      
         setCount(count => count + 1)}>+
         setCount(count => count - 1)}>-
      
      
      
        Class componnet:
        
      
      
        Function componnet:
        
      
    
  );
};

demo-1

be accomplished!

Problems encountered & summary

There are many times when react error boundaries are not everything. For example

  • Event error

demo-1
The above this. O does not exist, and an error will be reported. Window. Onerror can be captured, but the error boundary cannot be captured.

  • Asynchronous code

demo-1

  • Server side rendering and error boundary own errors

summary

  • Extraction assembly
  • Error feedback ✔
  • UI pull away ✔
  • Error reset ✔
  • Pull out hook mode ✖
  • Server ✖

So far, thank you for opening this article in your busy schedule. I hope it can help you. I believe you have a general understanding of the error boundary in react, and you will also write a simpleErrorBoundaryIn general, there are many optimization points. If you have any questions, you are welcome to correct them.

reference

Ask a star, thank you