错误边界


错误边界


部分 UI 的 JavaScript 错误不应该导致整个应用崩溃,为了解决这个问题,React 16引入了一个新的概念——错误边界。


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


我们来看一个例子:

// App.jsx
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 ChildCom2() {
return (
<div
style={{
width: "300px",
height: "300px",
border: "1px solid",
}}>ChildCom2</div>
);
}
export default ChildCom2;



function getData() {
return;
}
function ChildCom3() {
const arr = getData();
const spanContent = arr.map((item) => <span>{item}</span>);
return (
<div
style={{
width: "100px",
height: "100px",
border: "1px solid",
}}
>
ChildCom3
<div>{spanContent}</div>
</div>
);
}
export default ChildCom3;


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

App
/ \
ChildCom1 ChildCom2
/
(ChildCom3)

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


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


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


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


如果一个class组件中定义了static getDerivedStateFromError()或componentDidCatch()这两个生命周期方法中的任意一个(或两个) 时,那么它就变成一个错误边界。当抛出错误后,请使用static getDerivedStateFromError()渲染备用UI,使用componentDidCatch()打印错误信息。

// components/ErrorBoundart.jsx
import React from "react";
export default class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
// 这边需要你维护一个状态,该状态用来标记是否有错误
this.state = {
hasError: false,
};
}
static getDerivedStateFromError(error) {
console.log("error!!!", error);
return {
hasError: true,
};
}
componentDidCatch(error, errorInfo) {
console.log("error>>>", error);
console.log("errorInfo>>>", errorInfo);
// 一般可以把错误信息上传到服务器用来错误监控
}
render() {
if (this.state.hasError) {
// 说明有错误,渲染自定义的降级UI
return <div>出错了!!!</div>;
}
// 没有进入上面的if,说明没有错误,那直接渲染子组件树
return this.props.children;
}
}

然后我们给 ChildCom3 外面包裹一下这个组件

<ErrorBoundary>
<ChildCom3 />
</ErrorBoundary>

然后我们就会发现页面不会崩溃了,ChildCom3的位置出现了我们降级 UI 渲染的东西

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

  1. getDerivedStateFromError 静态方法
  2. 运行时间点:渲染子组件的过程中,发生错误之后,在更新页面之前(整个应用没有崩溃,直接渲染降级 UI)
  3. 注意:只有子组件发生错误,才会运行该函数
  4. 该函数返回一个对象,React 会将该对象的属性覆盖掉当前组件的 state
  5. 参数:错误对象
  6. 通常,该函数用于改变状态
  7. componentDidCatch 实例方法
  8. 运行时间点:渲染子组件的过程中,发生错误,更新页面之后(整个应用已经崩溃,之后再重新渲染整个应用,当然会将有问题的UI渲染成降级UI),由于其运行时间点比较靠后,因此不太会在该函数中改变状态
  9. 通常,该函数用于记录错误信息

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


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

  1. 事件处理
  2. 异步代码(例如 setTimeout 或者 requestAnimationFrame 回调函数)
  3. 服务端渲染
  4. 它自身抛出来的错误(并非它的子组件)

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


0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
晨晨
下载 APP