React 16增加新概念“异常边界”,让你更好的处理模块内异常

738 阅读4分钟

在已经发布的React 16 第一个beta版和即将发布的React 16中,添加了一个新的特性,用来处理React组件内的异常。
这个新特性是React提出的一个新的概念,叫“异常边界(Error Boundary)”。
如果你有兴趣,可以在React 16的beta版中体验一下。
阅读全文约4分钟。

本文同步发布与知乎专栏:前端微志。

什么是异常边界

在React 15和更早的版本中,组件内的JavaScript异常会污染React组件内的state,并且会在render时发出不明所以的异常。这些异常一般是由于系统运行过程中更多出现的异常,但是React没有提供一个组件内优雅地解决它们的方法,也不能恢复这些异常。

在开发者看来,用React做的一个大型系统上,UI页面上一个JavaScript代码的小小的异常,不应该影响整个系统的运行,这本来是浏览器在渲染JavaScript时默认采用的一种解析方式,但一般用React来做一个单页面应用(SPA)会把很多页面的代码打包到一起,如果一个JavaScript的报错导致整个系统不能运行,也是一件很糟糕的事情。


所以,这也算是React的设计上的一个小的缺陷,React为了帮助开发者解决这个问题,在React 16这一版中,将引入一个新概念“异常边界”,使用异常边界的组件就是异常边界组件。


异常边界是一个用来捕获组件的子组件树内的JavaScript异常,将这些异常记录下来,并显示一个回调的UI来替换掉崩溃的组件树。


异常边界组件会在组件render过程中,生命周期函数内和组件下的整个树形组件的构造函数内运行。

怎么使用异常边界

为了实现异常边界,React为组件提供了一个新的生命周期函数:

componentDidCatch(error, info)

请看下面的栗子,我们来包装一个异常边界组件:

class ErrorBoundary extends React.Compoent {
  constructor(props) {
    super(props);          
   this.state = { hasError: false };  }  componentDidCatch(error, info) {          
   // 显示回调UI    this.setState({ hasError: true });          
   // 你也可以将异常记录到一个异常报警服务上    logErrorToMyServer(error, info);  }  render() {          
   if (this.state.hasError) {              
     // 你可以render任何自定义的回调UI      return <h1>Something went wrong.</h1>;    }          
   return this.props.children;  } }

然后,你就可以将异常边界组件当做一个公用组件使用,如用它来包裹其他子组件,用于捕获子组件内的JavaScript异常。举个🌰:

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

异常边界的特性

通过上面的例子,你可能会觉得,componentDidCatch() 特别像JavaScript中的 catch() 方法块,只不过后者是用于JavaScript语句中的异常捕获,前者是用于React组件UI渲染过程中的异常捕获。

在使用异常边界时,需要注意几点:

  • 只有类组件(class components)可以被设置成异常边界组件

  • 通常情况下,你可能只声明一次异常边界组件,然后在整个项目中使用,当然你也可以设置多个

  • 异常边界组件只能捕获它的子组件树上的组件的异常,且不能捕获该组件自身产生的异常

  • 如果异常边界组件在捕获到一个异常后,渲染异常信息失败了,那么这个异常会向着该异常边界组件的父级向上传递,直到传递到最近的一个异常边界组件为止

在哪里设置异常边界组件

在项目中设置异常边界组件的颗粒度取决于开发者自己。

你可以像服务端渲染框架一样,在页面根路由组件上设置异常边界边界向用户展示“Something went wrong”这样的信息。

你也可以将单个组件用一个异常边界组件包裹起来,以防止这些组件崩溃时导致系统挂掉。

参考

https://facebook.github.io/react/blog/2017/07/26/error-handling-in-react-16.html