简要介绍:在之前的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组件本身的错误