Skip to content

错误边界

7. 错误边界#

这是从 React 16 引入了一个新的概念,为了解决的问题就是一个组件出错不至于整个应用崩溃。

首先我们还是来看一个示例:

import React from 'react'
import ChildCom1 from './components/ChildCom1'
import ChildCom2 from './components/ChildCom2'
function App() {
return (
<div>
<ChildCom1 />
<ChildCom2 />
</div>
)
}
export default App
import ChildCom3 from './ChildCom3'
function ChildCom1() {
return (
<div
style={{
width: '300px',
height: '300px',
border: '1px solid',
}}
>
ChildCom1
<ChildCom3 />
</div>
)
}
export default ChildCom1
function getData() {
return
}
function ChildCom3() {
const arr = getData()
const spanContent = arr.map((it) => <span>{it}</span>)
return (
<div
style={{
width: '100px',
height: '100px',
border: '1px solid',
}}
>
ChildCom3
<div>{spanContent}</div>
</div>
)
}
export default ChildCom3
function ChildCom2() {
return (
<div
style={{
width: '300px',
height: '300px',
border: '1px solid',
}}
>
ChildCom2
</div>
)
}
export default ChildCom2

在上面的代码中,我们整个组件树结构如下:

image-20221208145452107

可以看到,ChildCom1 下面的 ChildCom3 存在问题,这一个组件的问题会导致整个应用崩溃。

这在某些场景下,实际上是没有必要的,例如有问题的组件是广告、或者一些无关紧要的组件,此时我们就期望渲染出问题组件以外的组件树。

错误边界就是用来解决这个问题的。

错误边界是一种 React 组件,这种组件可以捕获发生在其子组件树任何位置的 JavaScript 错误,并打印这些错误,同时展示降级 UI,而并不会渲染那些发生崩溃的子组件树。错误边界可以捕获发生在整个子组件树的渲染期间、生命周期方法以及构造函数中的错误。

components/ErrorBoundary.jsx
import React, { Component } from 'react'
export default class ErrorBoundary extends Component {
constructor(props) {
super(props)
this.state = { hasError: false }
}
static getDerivedStateFromError(error) {
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true }
}
componentDidCatch(error, errorInfo) {
// 你同样可以将错误日志上报给服务器
console.log('error>>>', error)
console.log('errorInfo>>>', errorInfo)
}
render() {
if (this.state.hasError) {
// 你可以自定义降级后的 UI 并渲染
return <h1>Something went wrong.</h1>
}
return this.props.children
}
}

在上面的代码中,我们就创建了一个错误边界组件,该组件有一个 getDerivedStateFromError 静态方法以及 componentDidCatch 实例方法,这两个方法都会在组件渲染出错时调用,但是略有区别,具体的区别如下:

最佳实践,使用 static getDerivedStateFromError 渲染备用 UI ,使用 componentDidCatch 打印错误信息。

之后,我们就使用这个错误边界组件来包裹要忽略渲染错误的子组件,例如:

import ChildCom3 from './ChildCom3'
import ErrorBoundary from './ErrorBoundary'
function ChildCom1() {
return (
<div
style={{
width: '300px',
height: '300px',
border: '1px solid',
}}
>
ChildCom1
<ErrorBoundary>
<ChildCom3 />
</ErrorBoundary>
</div>
)
}
export default ChildCom1

有了错误边界组件后,ChildCom3 组件中的渲染错误并不会导致整个应用崩溃。效果如下:

image-20221208145524497

最后需要注意的是,错误边界组件主要是用来捕获 UI 渲染时的错误,因此如下场景中错误是无法捕获的:

总之,错误边界组件仅能过处理渲染子组件期间同步错误


-EOF-