2022年前端React的100道面试题的第15题:错误边界

291 阅读2分钟

问题

React17 中错误边界(Error Boundaries)能正常捕获错误的场景有哪些?

选项

A. 绑定DOM的事件方法中的错误。

B. 异步代码中的错误。

C. 任意子组件树的渲染方法 render() 和所有生命周期方法中的错误。

D. 错误边界组件自身的错误。

答案

C

纠错

A. 绑定DOM的事件处理方法中的错误无法被捕获到。(因为在触发交互前,组件的生命周期和渲染都已经被执行。如果需要捕获事件的方法中的错误,需要使用 JS 的 try / catch 方法。)

B. 异步代码中的错误无法被捕获到。(包括 setTimeout、Promise 等,原因与A同理。)

D. 错误边界组件自身错误无法被捕获,而是会被上层的错误边界组件给获取。

解答

错误边界是一种 React 组件,这种组件可以捕获发生在其子组件树任何位置的 JavaScript 错误,并打印这些错误,同时展示降级 UI,而并不会渲染那些发生崩溃的子组件树。

错误边界组件

在 class 组件中定义了 static getDerivedStateFromError()componentDidCatch() 这两个生命周期方法中的任意一个(或两个)时,那么它就变成一个错误边界。

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
​
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
​
  componentDidCatch(error, errorInfo) {
    logErrorToMyService(error, errorInfo);
  }
​
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children; 
  }
}

当抛出错误后,请使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息。

备注:只有 class 组件才可以成为错误边界组件。

错误边界原理

当组织树种没有定义错误边界组件时,React16 之后的版本就会卸载掉报错的组件树。它和 try / catch 机制是完全一样的,假设有如下结构的4个组件:

  • CompA
    • CompB
      • CompC1
      • CompC2

在没有错误边界的情况下,我们在 CompC1 的 render() 中抛出一个 Error 后,会导致上面的所有组件都被卸载掉。这时我再加入上面定义的错误边界组件来 catch 错误,调整如下:

  • CompA
    • CompB
      • ErrorBoundary
        • CompC1
        • CompC2

同样在 CompC1 组件抛出错误时,CompC1 和 CompC2 会被卸载掉,并且会启用 ErrorBoundary 组件中的 render 内容错误信息。

错误信息

假设我们在 render() 中抛出一个 new Error('I crashed!') 的错误时,可以在 componentDidCatch(error, errorInfo) 方法中会获得对应的错误详细信息,这里的 errorInfo 中的 componentStack 为 React 提供的组件堆栈信息。

in BuggyCounter (created by App)
in ErrorBoundary (created by App)
in div (created by App)
in App

而 err 对象为原生的 Error 对象,使用 error.toString() 可以打印出具体的报错描述: I crashed!

资料

zh-hans.reactjs.org/docs/error-…

来源

搜索《考试竞技》微信小程序