错误边界
- React16增加
- 防止某个组件的UI渲染错误导致整个应用崩溃
- 子组件发生JS错误,有备用的渲染UI
- 错误边界是组件,只能用class组件来写
错误边界组件捕获错误的时机
- 渲染时
- 生命周期函数中
- 组件树的构造函数中
getDerivedStateFromError
- 生命周期函数 static getDerivedStateFromError(error)
- 参数:子组件抛出的错误
- 返回值:新的state
- 渲染阶段调用
- 作用:不允许出现副作用(异步代码、操作dom等)
componentDidCatch
- 生命周期函数
- 组件原型上的方法
- 边界组件捕获异常,并进行后续处理
- 作用:错误信息获取,运行副作用
- 在组件抛出错误后调用
- 参数:error(抛出的错误)、info(组件引发错误相关的信息,即组件栈)
componentDidCatch(err, info) {console.log('componentDidCatch err', err)console.log('componentDidCatch info', info)
}
无法捕获的场景
- 1.事件处理函数(无法显示备用UI)
function Correct() {const handleClick = () => {console.log('点击')throw new Error('click throw err')}return (<div onClick={handleClick}>正常显示内容</div>)
}
<ErrorBoundary><Correct />
</ErrorBoundary>
- 2.异步 setTimeout、ajax
function Correct() {const err = () => {setTimeout(() => {throw new Error('抛出错误')}, 1000)}err()return (<div>正常显示内容</div>)
}
<ErrorBoundary><Correct />
</ErrorBoundary>
- 3.服务端渲染
- 4.错误边界组件(
ErrorBoundary
)内部有错误
class ErrorBoundary extends React.Component {state = {hasError: false,}static getDerivedStateFromError() {return {hasError: true}}render() {if (this.state.hasError) {return (<h1>This is Error UI{data}</h1>)}return this.props.children}
}
<ErrorBoundary><TestErr />
</ErrorBoundary>
以上几种情况有可能导致整个React组件被卸载
示例代码
class ErrorBoundary extends React.Component {state = {hasError: false,}static getDerivedStateFromError() {return {hasError: true}}render() {if (this.state.hasError) {return (<h1>This is Error UI</h1>)}return this.props.children}
}
function TestErr() {return (<h1>{data}</h1>)
}
function Correct() {return (<div>正常显示内容</div>)
}
function App() {return (<div><ErrorBoundary><TestErr /></ErrorBoundary><Correct /></div>)
}
ReactDOM.render(<App />,document.getElementById('app')
)
错误边界组件能向上冒泡
TestErr
有错误,冒泡到ErrorBoundary
,ErrorBoundary
自身也有错误- 如果多个嵌套错误边界组件 → 则从最里层错误触发、向上冒泡触发捕获
<ErrorBoundary2><ErrorBoundary><TestErr /></ErrorBoundary>
</ErrorBoundary2>
- 在开发模式下,错误会冒泡至window,而生产模式下,错误不会冒泡,详见文档
class ErrorBoundary2 extends React.Component {constructor(props) {super(props)window.onerror = function (err) {console.log('window.onerror err', err)}}state = {hasError: false,}static getDerivedStateFromError(err) {return {hasError: true}}render() {if (this.state.hasError) {return (<h1>This is Error UI2</h1>)}return this.props.children}
}