一、描述

错误边界 是 React 的一种组件树,能够在子组件树中的任何位置捕获 JavaScript 错误,并且能够打日志或者是显示错误情况下的UI组件。

错误边界能够在渲染期间、生命周期方法以及它们下面的整个树的构造函数中捕获错误。

如果一个类组件定义了下面生命周期方法中的任何一个或者是两个,则这个类组件将成为一个错误边界:

  • static getDerivedStateFromError()
  • componentDidCatch()

从上面的生命周期方法中可以捕获未处理的 javascript 错误,并且可以更新状态显示错误界面的UI。

错误边界的使用也有一定的要求:

  • 只能使用错误边界来捕获异常或者是从异常中恢复
  • 不能将错误边界用于控制流程

更多错误边界的信息可以看错误边界的文档:

注意

错误边界还能捕获树中子组件的错误,错误边界是不能捕获本身的错误。

二、static getDerivedStateFromError()

getDerivedStateFromError(err) 这个方法会在子组件抛出错误后调用,接收的参数 err 是子组件抛出的错误,而在这个组件中,应当更新 state,来更新整个组件的呈现方式。

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
  static getDerivedStateFromError(error) {
    // 更新状态来显示错误触发的UI
    return { hasError: true };
  }
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children; 
  }
}

注意

getDerivedStateFromError() 是在 render 阶段调用的,因此不允许在 getDerivedStateFromError() 中进行副作用,如果要使用副作用用例,可以使用 componentDidCatch()

三、componentDidCatch()

componentDidCatch(error, info) 这个生命周期会在子组件抛出错误的时候调用,主要接收两个参数:

componentDidCatch() 是在 commit 阶段被调用的,因此允许进行副作用,比如需要记录错误信息的情况:

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // 在这里更新 state
    return { hasError: true };
  }
  componentDidCatch(error, info) {
    // 示例:"componentStack":
    //   in ComponentThatThrows (created by App)
    //   in ErrorBoundary (created by App)
    //   in div (created by App)
    //   in App
    logComponentStackToMyService(info.componentStack);
  }
  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children; 
  }
}

注意

如果发生错误,可以调用 setState 来使用 componentDidCatch 渲染错误信息的 UI,但是这种方式在将来版本中讲不可用。

如果要渲染错误信息的 UI,应当在 getDerivedStateFromError() 中进行处理。