React 16.0中的新特性——Error Boundaries及其注意点

来源:互联网 发布:计算年龄的软件 编辑:程序博客网 时间:2024/06/06 04:24

简要介绍:在之前的React版本中规定,如果在组件中javascript报错,那么会在下一次的render中阻断,并且现实空白页。React之前没有提供一种合适的处理组件错误的方法,而React16.0中通过Error Boundaries来处理组件内部的错误,从而可以修正错误组件。

1.什么是Error Boundaries?

单一组件内部错误,不应该导致整个应用报错并显示空白页,而Error Boundaries解决的就是这个问题。

(1)Error Boundaries的实现

如何使组件变成一个“Error Boundaries”,只需要在组件中定义个新的生命周期函数——componentDidCatch(error, info)

class ErrorBoundary extends React.Component {  constructor(props) {    super(props);    this.state = { hasError: false };  }  componentDidCatch(error, info) {    // Display fallback UI    this.setState({ hasError: true });    // You can also log the error to an error reporting service    logErrorToMyService(error, info);  }  render() {    if (this.state.hasError) {      // You can render any custom fallback UI      return <h1>Something went wrong.</h1>;    }    return this.props.children;  }}

上述的ErrorBoundary就是一个“错误边界”,然后我们可以这样来使用它:

<ErrorBoundary>  <MyWidget /></ErrorBoundary>

Erro Boundaries本质上也是一个组件,通过增加了新的生命周期函数componentDidCatch使其变成了一个新的组件,这个特殊组件可以捕获其子组件树中的js错误信息,输出错误信息或者在报错条件下,显示默认错误页。

注意一个Error Boundaries只能捕获其子组件中的js错误,而不能捕获其组件本身的错误和非子组件中的js错误。

(2)componentDidCatch()生命周期函数

componentDidCatch是一个新的生命周期函数,当组件有了这个生命周期函数,就成为了一个Error Boundaries。下面我们来看componnetDidCatch()中的参数:

componentDidCatch(error, info) {}

error参数,表示的是被抛出的错误的信息,而info是一个对象包含了组件堆栈中的信息(也就是在发生错误的子组件中层层传递错误信息,到顶层的Error Boundaries,每一层中的组件名)。

(3)Component Stack Traces

下面我们来看组件堆栈轨迹,我们假设这样一个结构:

<App>  <div>      <ErrorBoundary>        <Child></Child>      </ErrorBoundary>  </div></App>

如果在Child组件中发生了js错误,那么堆栈的报错信息应该如下:

the error is located at :     in Child  (created by App)     in ErrorBoundary(created by App)     in div (created by App)     in App

如果需要报错信息显示错误组件所在的具体的行数和位置,可以使用babel-plugin-transform-react-jsx-source插件。

(4)try/catch模块

我们使用了Error Boundaries来抛出组件的内部异常,那么什么时候可以使用try / catch模块呢。我们知道Error Boundaries仅仅抛出了子组件的错误信息,并且不能抛出组件中的事件处理函数中的异常。(因为Error Boundaries仅仅能保证正确的render,而事件处理函数并不会发生在render过程中),我们需要用try/catch来处理事件处理函数中的异常,举例来说:

class MyComponent extends React.Component {  constructor(props) {    super(props);    this.state = { error: null };  }  handleClick = () => {    try {      // Do something that could throw    } catch (error) {      this.setState({ error });    }  }  render() {    if (this.state.error) {      return <h1>Caught an error.</h1>    }    return <div onClick={this.handleClick}>Click Me</div>  }}

上述的代码中,我们在 MyComponent组件的handleClick 通过try/catch的方式来抛出异常,与一般javascript的异常处理方式相同。

2.注意事项

下面我们来看哪些情况下不能通过Error Boundaries来实现catch{}错误

(1)组件的内部的事件处理函数,因为Error Boundaries处理的仅仅是Render中的错误,而Hander Event并不发生在Render过程中。

(2)异步函数中的异常,Error Boundaries不能catch,比如setTimeout或者setInterval ,requestAnimationFrame等函数中的异常。

(3)服务器端的rendering

(4)发生在Error Boundaries组件本身的错误