React.js - 错误边界

React.js - ErrorBoundary

我不太确定,如果我完全理解 React 的概念 ErrorBoundary。 我需要说,我真的想开始使用 ErrorBoundary,但我是第一次使用它。

所以我创建了一个 ErrorBoundary 组件:

import React, { Component } from "react";
import * as Data from '../../backend/data';

class ErrorBoundary extends React.Component {
    constructor(props) {
      super(props);
      this.state = { hasError: false };
    }
  
    componentDidCatch(error, stackTrace) {
      this.setState({ hasError: true  });
      console.log(error, stackTrace);
      // Send error to backend
      Data.trackError(error, stackTrace.componentStack, this.props.component, this.props.location, this.props.guestLandingPage?.identifier_token, this.props.user?.id);
    }
  
    render() {
      if (this.state.hasError) {
        return this.props.fallbackUI;
      }
  
      return this.props.children; 
    }
}

export default ErrorBoundary;

现在我尝试在我的 app.container.js 中使用它(我不会复制它的全部代码,只复制它的必要部分):

...
import NavBarComponent from './components/navbar.component';
import ErrorBoundary from './components/error/error.component';
import FallbackUI from './components/error/standardFallback.component';
...
class App extends Component {
...
    render() {
        const View = this.importView();
        return (
                    <ErrorBoundary
                        location={"builder"}
                        component={"app.container.js"}
                        user={this.props.user}
                        fallbackUI={<FallbackUI />}
                    >
                        <Wrap>
                            <NavBarComponent
                                key={"navBarComponent"}
                            />
                            ...
                        </Wrap>
                    ...
                    </ErrorBoundary>
        )
    }
}

然后我开始手动创建一个错误。我在我的 navbar.component.js 中添加了一个变量,该变量不存在并导致抛出错误。

到目前为止一切正常。错误被发送到后端并显示我的回退 UI 组件。 到目前为止,还不错。

但是,现在我不想在顶层捕获错误,而是在各个组件中捕获错误,这样应用程序仍然可用,并且仅在发生错误时在各个组件中显示错误消息. 因此,我现在已将 ErrorBoundary 组件移至 navbar.component.js(并将其从 app.container.js 中删除)。

class NavBarComponent extends Component {
    ...
    render() {
        return (
            <ErrorBoundary
                location={"builder"}
                component={"navbar.component.js"}
                user={this.props.user}
                fallbackUI={<FallbackUI />}
            >
               <Nav className="navbar navbar-expand-lg navbar-light">
                   ...
               </Nav>
            </ErrorBoundary>
       );
    }
}

...期待相同的结果,但仅在显示导航栏的地方显示我的后备 UI 组件。 但实际上结果是 ErrorBoundary 在移动到导航栏时根本没有被触发。 为什么?是不是每个组件本身都加上ErrorBoundary组件,这样就只显示出错的组件,不显示整个app? 非常感谢您提前对此做出任何解释!

PS:我也想知道,为什么我不能在我的 ErrorBoundary 组件中同时使用 getDerivedStateFromErrorcomponentDidCatch 方法。当在 ErrorBoundary 中定义 getDerivedStateFromError 方法时,从未调用方法 componentDidCatch:

static getDerivedStateFromError(error) {
    return { hasError: true };
}

...但据我所知,仅使用 componentDidCatch.

即可正常工作

由于错误发生在 navbar.component.js 中,ErrorBoundary 必须存在于其 parent 层次结构中的某处。目前,您将其用作 navbar.component.js

的 child

将 ErrorBoundary 用法更新为以下应该会像您预期的那样工作

class App extends Component {
...
    render() {

        const View = this.importView();
        return (
            <Wrap> 
                <ErrorBoundary
                        location={"builder"}
                        component={"app.container.js"}
                        user={this.props.user}
                        fallbackUI={<FallbackUI />}
                 >
                            <NavBarComponent
                                key={"navBarComponent"}
                            />
                  </ErrorBoundary>
                            ...
             </Wrap>
             ...
                    
        )
    }
}

您还可以通过使用 ErrorBoundary 包装组件来导出组件,这样您就不必在渲染组件的任何地方都这样做

export default ({location, user, ...props}) => {
   return ( 
       <ErrorBoundary
            location={location}
            component={"navbar.component.js"}
            user={user}
            fallbackUI={<FallbackUI />}
       >
                <NavBarComponent
                    key={"navBarComponent"}
                    {...props}
                />
      </ErrorBoundary>
  )
}

并像

一样使用它
class App extends Component {
...
    render() {
        const View = this.importView();
        return (
            <Wrap>
                <NavBarComponent
                    location={"builder"}
                    user={this.props.user}
                    key={"navBarComponent"}
                />
                ...
            </Wrap>
        )
    }
}