react中封装报错边界ErrorBoundary

99 阅读2分钟

背景:

在日常开发中,有时候因为种种 原因,代码会报错,最终导致页面崩溃的结果;这种情况会给 用户非常不好的体验;所以,我们可以做一个报错边界;即封装这么一个报错组件,然后将业务组件被该组件包裹,这样业务组件即使报错,也不过逃出这个边界,即将报错控制在一定范围内,不至于让整个页面给崩溃了;同时在报错的情况下,还能在页面进行一定的提示;一来用户比较好的提示;二来,直接能知道是哪个组件发生了错误,能快速定位到。

封装的报错边界组件:

import React, { ReactNode } from 'react';


export class ErrorBoundary extends React.Component<{ children: React.ReactNode, displayText?: string }, { hasError: boolean }> {
    /**
     * 构造函数用于ErrorBoundary组件的初始化
     * @param props - 传递给组件的属性
     * @return 没有返回值
     */
    constructor(props: { children: ReactNode; displayText?: string }) {
        super(props);
        this.state = {
            hasError: false,
            Error: null,
            ErrorInfo: null,
        };
    }

    /**
     * 捕获错误并更新状态以指示发生了错误
     * @param error - 发生的错误。
     * @return 更新后的状态,其中hasError设置为true。
     */
    static getDerivedStateFromError(error: any) {
        // 更新 state 使下一次渲染能够显示降级后的 UI
        return { hasError: true };
    }

    /**
     * 在渲染过程中捕获错误并使用错误信息更新状态的生命周期
     * @param error - 被捕获的错误。
     * @param errorInfo - 关于错误的额外信息。
     */
    componentDidCatch(error: any, errorInfo: any) {
        //记录错误日志
        console.error("ErrorBoundary caught an error:", error, errorInfo);
    }

    /**
     * 根据错误状态渲染组件
     * @return 基于错误状态渲染的内容
     */
    render() {
        // if (this.state.hasError) {
        //     return <div>{this.props?.displayText || "渲染出错了,检查控制台"}</div>;
        // }

        // return this.props.children;
        const { hasError, Error, ErrorInfo } = this.state;
        const { children } = this.props;
        // 如果捕获到异常,渲染降级UI
        if (hasError) {
        return (
            <div>
            {/* 错误信息 */}
            <h1>{`Error:${Error?.message}`}</h1>
            {/* 错误栈 */}
            <details style={{ whiteSpace: "pre-wrap" }}>{ErrorInfo?.componentStack}</details>
            </div>
        );
        }
        return children;
    }
}


调用:

<div>
    <ErrorBoundary key="ComponentA" displayText='ComponentA渲染出错'>
        <ComponentA params={params} />
    </ErrorBoundary>

    <ErrorBoundary key="ComponentB" displayText='ComponentB出错'>
        <ComponentB ref={childRef} {...{ menuId, createName, form}} />
    </ErrorBoundary>
</div>