过去,组件内的Javascript错误会导致React的内部状态被破坏,并且在下一次渲染时候产生可能无法追踪的错误。这些基本上是由较早的其他代码(非react组件代码)错误引起的,但react没有提供一种在组件中优雅的处理这些错误的方式,也无法从错误中恢复。
错误边界
部分UI的错误不应该导致整个应用崩溃,为了解决这个问题,react16引入了一个新的概念,错误边界
错误边界是一种react组件,这种组件可以捕获并打印发生在其子组件树任何位置的JavaScript错误,并且,他会渲染出备用的UI而不是渲染那些崩溃了的子组件树。错误边界在渲染期间,生命周期方法和整个组件树构造函数中捕获错误
注意:错误边界无法捕获到以下场景中产生的错误
- 事件处理
- 异步代码(setTimeout 或 requestAnimationFrame 回调函数)
- 服务端渲染
- 它自身抛出来的错误(并非它的子组件)
如果一个class组件定义了 static getDerevedStaticFormatError
或者 ComponentDidCatch
这两个生命周期的任意一个(或者两个)时,那它就变成一个错误边界,当抛出错误时,请使用static getDerevedStaticFormatError
渲染备用UI,ComponentDidCatch
打印错误信息
示例
import React from 'react'
class ErrorBoundaries extends React.Component{
constructor (props) {
super(props);
this.state = {
error:null,
errorInfo:null
}
}
static getDeruvedStateFromError(error){
return {
error: error
}
}
componentDidCatch (error, errorInfo) {
this.setState({
error:error,
errorInfo:errorInfo
})
}
render () {
if(this.state.errorInfo){
return (
<div>
<h1>Something went wrong</h1>
<div style={{whiteSpace:'pre-wrap'}}>
{this.state.error && this.state.error.toString()}
<br/>
{this.state.errorInfo.componentStack}
</div>
</div>
)
}
return this.props.children
}
}
class BuggyCounter extends React.Component{
constructor (props) {
super(props);
this.state = {
counter:0
}
this.handleClick = this.handleClick.bind(this)
}
handleClick(){
this.setState(state => ({
state,
counter:state.counter + 1
}))
}
render () {
if(this.state.counter === 5){
throw new Error('I crashed')
}
return (
<h1 onClick={this.handleClick}>{this.state.counter}</h1>
)
}
}
class App extends React.Component{
constructor (props) {super(props);}
render () {
return(
<div>
<p>
<b>
This is an example of error boundaries in React 16
<br/>
<br/>
Click on the numbers to increase the counters
<br/>
The counter is programed to throw when it reaches 5.This simulates a JavaScript error in a component
</b>
</p>
<br/>
<ErrorBoundaries>
<p>These two counters are inside the same error boundary if one crashes the error boundary will replace both of them</p>
<BuggyCounter></BuggyCounter>
<BuggyCounter></BuggyCounter>
</ErrorBoundaries>
<br/>
<p>These two counters are each inside of their own error boundary. so if one crashes,hte other is not affected</p>
<ErrorBoundaries>
<BuggyCounter></BuggyCounter>
</ErrorBoundaries>
<ErrorBoundaries>
<BuggyCounter></BuggyCounter>
</ErrorBoundaries>
</div>
)
}
}
export default App
错误边界的芳芳应该放在那里?
可以包装在最顶层的路由组件,也可以单独放在组件外