2

我不太确定,如果我完全理解 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:我也想知道,为什么我不能在我的组件中同时使用getDerivedStateFromErrorandcomponentDidCatch方法。ErrorBoundary在 中定义getDerivedStateFromError方法时ErrorBoundary,该方法componentDidCatch从未被调用:

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

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

4

1 回答 1

3

由于错误发生在 中navbar.component.js,因此ErrorBoundary必须存在于其父层次结构中的某个位置。目前,您将其用作navbar.component.js

将 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>
        )
    }
}
于 2021-07-02T07:26:26.233 回答