React.js |错误边界

前言:做笔记,参考:react文档,文章涉及的示例:https://sanhuamao1.coding.net/public/note/myapp/git/files/13Error-Boundaries

错误边界

错误边界是一种 React 组件,可以捕获并打印发生在其子组件树任何位置的 JavaScript 错误,并且渲染出备用 UI。错误边界在渲染期间、生命周期和整个组件树的构造函数中捕获错误。

它无法在以下场景捕获错误:

  • 事件处理(了解更多)
  • 异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)
  • 服务端渲染
  • 它自身抛出来的错误(并非它的子组件)

使用方式

这是两种生命周期方法。只要class组件用了任意一种,那它就变成一个错误边界组件


方式一:componentDidCatch()

class ErrorBoundary extends React.Component {
    constructor(props) {
      super(props);
      this.state = { hasError: false };
    }
    componentDidCatch(error, errorInfo) {
      this.setState({
          error:error,
          errorInfo:errorInfo
      })
    }
    render() {
      if (this.state.errorInfo) {
        return <div>
            {this.state.error&&this.state.error.toString()}<br/> {this.state.errorInfo.componentStack}
        </div>
        
      }
      //正常则返回子元素,即该组件包裹的元素
      return this.props.children; 
    }
 }

一个测试组件,如果输入的是非字母就会报错:

class Example extends React.Component{
    constructor(props){
        super(props)
        this.state={value:""}
        this.handleChange=(e)=>{
            this.setState({value:e.target.value})
        }
    }
    render(){
        const value=this.state.value
        if(/^[a-zA-Z]+$/.test(value)||value===""){
            return  <input type="text" onChange={this.handleChange} placeholder="只能填字母"/>
        }
        throw new Error('出错了!');
    }
}

App.js

<ErrorBoundary>
   <Example />
</ErrorBoundary>

方式二:static getDerivedStateFromError()

class ErrorBoundary extends React.Component {
    constructor(props) {
      super(props);
      this.state = { hasError: false };
    }
    static getDerivedStateFromError(error) {
      return { hasError: true };
    }
    
    render() {
      if (this.state.hasError) {
        //显示降级UI
        return <div>出错了bro!</div>
      }
      return this.props.children; 
    }
 }

image.png


你也可以同时使用两种。

看样子componentDidCatch()好像没什么用,因为一般情况下浏览器会告诉你只能在控制台看错误日志,并且在没有使用该错误边界组件的情况下,控制台也会打印出同样的错误信息。相比之下,能渲染出备用组件的static getDerivedStateFromError()的实用性高一点。其实,无论使用哪一种,它都起到了创建错误边界组件的作用。

错误边界组件的工作方式类似于 JavaScript 的 catch {},不同之处在于它只针对 React 组件。且只有 class 组件才可以成为错误边界组件。注意,它无法捕获其自身的错误。

如果没有使用错误边界会怎样?

自 React 16 起,任何未被错误边界捕获的错误将会导致整个 React 组件树被卸载。

经验告诉我们,完全移除比保留错误UI更好。例如,在类似 Messenger 的产品中,把异常的 UI 展示给用户可能会导致用户将信息错发给别人。

增加错误边界能够让你在应用发生异常时提供更好的用户体验。例如,Facebook Messenger 将侧边栏、信息面板、聊天记录以及信息输入框包装在单独的错误边界中。如果其中的某些 UI 组件崩溃,其余部分仍然能够交互。

try/catch的缺陷

try / catch 很棒但它仅能用于命令式代码:

try {
  showButton();
} catch (error) {
  // ...
}

然而,React 组件是声明式,并且具体指出 什么 需要被渲染:

<Button />

为什么无法捕获事件处理器的内部错误?

React 不需要错误边界来捕获事件处理器中的错误。与 render 方法和生命周期方法不同,事件处理器不会在渲染期间触发。因此,如果它们抛出异常,React 仍然能够知道需要在屏幕上显示什么。如果你需要在事件处理器内部捕获错误,使用普通的 JavaScript try / catch 语句:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    try {
      // 执行操作,如有错误则会抛出
    } catch (error) {
      this.setState({ error });
    }
  }

  render() {
    if (this.state.error) {
      return <h1>捕获到一个错误</h1>
    }
    return <button onClick={this.handleClick}>点击</button>
  }
}
posted @ 2020-09-26 21:16  sanhuamao  阅读(645)  评论(0编辑  收藏  举报