持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情
错误边界(ErrorBoundry)介绍
我们知道在React项目中,如果某个React组件报错,但是这个错误没有被捕获就会导致整个React组件树被卸载,进而导致整个页面显示为白屏。
如果在项目使用中出现这种情况,客户体验感太差,开发人员跟踪问题也不方便。我们势必要解决此问题。
在React16 中,官方就这个问题,提出了“错误边界”这个概念,用于专门处理此问题。
原理: 利用
componentDidCatch这个声明周期,在render()函数抛出错误时,这个声明周期函数就可以捕捉到错误信息,然后我们将信息抛出,利于开发者迅速定位并处理问题。
全局级别的错误捕获
通过定制ErrorBoundry 组件,我们将业务逻辑组件包裹在此组件内,通过componentDidCatch钩子来获取错误信息,同时在Render方法中渲染报错后需要显示内容,这里可以根据需求,个性化定制样式。
组件定义
// 代码示例
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { error: null, errorInfo: null };
}
// 捕获事件,这是核心问题.
componentDidCatch(error, errorInfo) {
this.setState({
error: error,
errorInfo: errorInfo,
});
}
render() {
let { error, errorInfo } = this.state;
let { msgInfo } = this.props;
if (error) {
let { message } = error;
if (message) {
// Error(message);
}
if (msgInfo) {
return <div className="error-info-wrap">{msgInfo}</div>;
} else {
return <ErrorTemplate error={error} />;
}
}
// 正常页面,渲染子组件
return this.props.children;
}
}
组件使用
import ErrorBoundary from "components/ErrorBoundary";
render() {
return (
<ErrorBoundary>
<div className="route-content">
<Route exact path="/" component={ListContainer} />
<Route exact path="/edit" component={EditContainer} />
</div>
</ErrorBoundary>
);
}
为了保险起见,我们将该组件套在渲染Route的外面,这样在该单页面应用中,不论那层组件报错,我都可以顺利捕获。同时在页面和控制台输出报错信息。
组件级别的错误捕获
另外:为了能更精确的捕获错误发生的组件,也为了尽做大可能显示页面信息。 换句话说,为了保证页面上除了有错误的组件外其他组件的正常渲染。
我们在几个常用的核心组件中嵌入了刚才的ErroryBoundry组件。
如下:
// 这是表单核心组件
<ErrorBoundary msgInfo="表单字段报错!">
<Row className="pro-field-group">
{filedGroupDom}
{React.Children.count(children) > 0 &&
React.Children.map(children, (thisArg) => (
<Col {...curCol}>{thisArg}</Col>
))}
</Row>
</ErrorBoundary>
// 这是表格核心组件
<ErrorBoundary msgInfo="editTable 组件错误!">
<Grid columns={gridColums}
paginationObj={{ verticalPosition: "none" }}
columnFilterAble={rowEditStatus}
showHeaderMenu={rowEditStatus}
dragborder={rowEditStatus}
draggable={rowEditStatus}
syncHover={rowEditStatus}
{...otherProps}
/>
</ErrorBoundary>
注意点
- 在实际开发中,开发者只需要在根组件引入错误边界组件。不需要处理表格组件、表单组件中的错误边界。
ErroryBoundary仅仅可以捕获到被其包裹的组件的错误,而不能捕获到本身级别的错误,所以我把它放在路由节点的外面。- 它很像JS的
catch{}模块一样,但是对于组件,只有class类型的组件可以使用它。 - 它不能捕获异步代码,所以针对于异步请求的捕获,我们使用了
try/catch处理。
try {
const res = processData(
await commonRequest("verifyReport", { id: searchId })
);
if (res) {
const { result } = res;
const { success, data } = result;
if (success) {
// do sth...
}
}
} catch (error) {
Error(error);
}