React系列-错误边界

224 阅读2分钟

1. 错误边界是什么?

  • React中,组件的JavaScript错误不应该破坏整个应用程序。为了解决这个问题,React16引入了“错误边界”的新概念。
  • 错误边界也是 React 组件,它可以在子组件树的任何位置捕获 JavaScript 错误,记录这些错误,并显示一个备用UI(UI降级) ,而不是使整个组件树崩溃。

2. 错误边界有什么限制?

  • 无法捕获的错误
    • 事件中的错误,比如click事件中发生的错误
    • 异步代码 (例如 setTimeout 或 requestAnimationFrame 回调函数)
    • 服务端渲染
    • 错误边界自身抛出来的错误 (而不是其子组件)
  • 使用时只能是class组件
    • 错误边界组件目前只支持class组件的方式创建。

3. 如何实现一个错误边界?

  • 创建一个类组件,组件中包含getDerivedStateFromErrorcomponentDidCatch两个声明周期函数。

  • getDerivedStateFromError

    • 该函数为静态函数 static getDerivedStateFromError
    • 函数执行时间点:页面更新前,子组件渲染出现错误之后。
    • 只有子组件发生错误时,该函数才会被执行
    • 该函数返回一个对象,该对象的返回值会覆盖掉当前组件的state
    • 参数 错误对象Error
  • componentDidCatch

    • 捕捉错误生命周期函数
    • 参数:1. error:错误对象 {message:string, stack:string} 2.errorInfo 错误信息 {componentStack :string}
    • 基本用来处理错误产生之后的上报和错误处理逻辑。
    • 触发时间点:子组件报错后及组件更新之后。
  • 代码demo

    • ErrorBoundary组件
  import React from "react";
import { Button } from "antd"

class ErrorBoundary extends React.Component<{ children: React.ReactNode }> {
    state = {
        error: null,// 是否存在错误
        errMsg: ""
    }
    /**
     * 捕捉错误,并且将错误添加到state中
     * 若state存在该属性则覆盖,没有则添加
     * 
     * @param err 
     * @returns 
     */
    static getDerivedStateFromError(err: Error) {
        // 给state 中的error属性赋值
        return { error:err }
    }

    /**
     * 捕捉错误生命周期函数
     * @param error 错误对象 {message:string, stack:string}
     * @param errorInfo  错误信息 {componentStack :string}
     */
    componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
        console.log("componentDidCatch error ", error, errorInfo)
        // 上报错误或其他处理逻辑
        this.setState({
            errMsg: error
        })
    }
    
    render() {
        if (this.state.error) {
            // return <div>{this.state.errMsg}</div>
            return <div>
                <div>
                    The Error Message:{this.state.errMsg?.message}
                </div>
                <section>
                    someThing was Wrong !
                </section>
                <Button onClick={() => window.location?.reload()}>点击刷新</Button>
            </div>
        }
        return this.props.children;
    }
}

export default ErrorBoundary;
  • 使用
    • 错误边界的使用粒度按实际业务控制,比如只对某些容易出现错误的组件做包裹即可,不影响其他组件的展示。
      image.png
    • 效果
    • Header子组件故意触发错误 使用props.a.a(undefined.a)
    image.png

    子组件错误页面错误捕捉并且显示。 image.png