The error boundaries of react

Time:2021-6-24

Error boundaries

Starting from react V16, the concept of boundary error is introduced.

Core API

  1. getDerivedStateFromError
  2. componentDidCatch

1. Purpose: some UI crash, not the whole webapp crash

2. Attention ⚠️: Error bounds cannot capture errors in the following scenarios

  • Event handling (learn more)
  • Asynchronous code (for examplesetTimeoutorrequestAnimationFrameCallback function)
  • Server rendering
  • Errors thrown by itself (not its subcomponents)

3. Write error boundary components

import React, { Component } from 'react';

interface ErrorBoundaryProps { };
interface ErrorBoundaryState {
    hasError: boolean;
};

class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
    constructor(props: ErrorBoundaryProps) {
        super(props);
        this.state = {
            hasError: false
        };
    }

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

    componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
        //You can also report the error log to the server
        console.group();
        console.log('ErrorBoundary catch a error:');
        console.info('error', error);
        console.info('error info', errorInfo);
        console.groupEnd()
    }


    render() {
        console.log('component ErrorBoundary render...');
        const { children } = this.props;
        const { hasError } = this.state;
        // return (
        //     <>
        //         {
        //             hasError ? 'Something Wrong' : children
        //         }
        //     </>

        // )
        if (hasError) {
            return 'Something wrong';
        } else {
            return children;
        }
    }
}

export default ErrorBoundary;

4. Write a “error component”

Click the button to trigger + 1. When counter is 5, error will be thrown

import React, { Component } from 'react';

interface ErrorComponentProps { };
interface ErrorComponentState {
    counter: number;
};

class ErrorComponent extends Component<ErrorComponentProps, ErrorComponentState> {
    constructor(props: any) {
        super(props);
        this.state = {
            counter: 0
        }
        this.handleClick = this.handleClick.bind(this);
    }

    handleClick() {
        //Error in event handling, errorboundary cannot catch
        // if (this.state.counter === 5) {
        //     throw new Error();
        // }
        this.setState({
            counter: this.state.counter + 1
        });

    }

    render() {
        console.log('component ErrorComponent render...');
        const { counter } = this.state;
        const { handleClick } = this;
        if (counter === 5) {
            throw new Error('counter creashed!');
        }
        return (
            <>
                <p>this component will throw Error when the counter equal to 5</p>
                <p>counter : {counter}</p>
                <button onClick={handleClick}>add</button>
            </>
        )
    }
}

export default ErrorComponent;

5. Combination

import React from 'react';

import ErrorBoundary from './component/ErrorBoundary';
import ErrorComponent from './component/ErrorBoundary/ErrorComponent';

function App() {
  return (
    <div className="App">
        <ErrorBoundary>
          <ErrorComponent />
        </ErrorBoundary>

    </div>
  );
}

export default App;

6. Package static resources

>The reason for not testing devserver is that in the configuration of CRA, webpack will catch error and display error mask, which is not easy to see the test results

Add fields in package.json"homepage": "."

7. yarn build

8. Find index.html and test it!