熟悉React都知道,在React中一些UI的错误,比如throw new Error(),加载服务器资源报错时,或者一些js的语法错误可能会导致整个项目崩溃掉,满屏的红色报错,非常不友好。为了解决这个问题,React16引入了错误边界。就是在报错的情况下,可以通过static getDerivedStateFromError()和componentDidCatch()捕获到这个错误。
import React, { Component, lazy, Suspense } from 'react';
import Home from './home
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
console.log('getDerivedStateFromError') // 先打印出来
// 更新 state 使下一次渲染能够显示降级后的 UI
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 你同样可以将错误日志上报给服务器
console.log('componentDidCatch') // 后打印出来
this.setState({
hasError: true
})
}
render() {
if (this.state.hasError) {
// 你可以自定义降级后的 UI 并渲染
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
class App extends Component {
render() {
return (
<div>
<ErrorBoundary>
<Home></Home>
</ErrorBoundary>
</div>
)
}
}
export default App;
一般是像这样抽离出来一个ErrorBoundary的组件,将该组件包裹需要捕获错误的组件(本文中是Home组件),如果Home组件报错则改变ErrorBoundary中hasError的值。在render中判断是加载报错的jsx还是继续加载Home(ErrorBoundary的props.children)。或者可以学习Dan大神的这个Demo:https://codepen.io/gaearon/pen/wqvxGa?editors=0010。
然而,我更想说的是它的坑点。首先,本人经过多次、多react版本的实验,得知在16.8版本中用起来很靠谱的错误边界,在最新版本(至此篇博客发表是17.0.2)是无法正常使用的。虽然static getDerivedStateFromError和componentDidCatch中的log都能按和16版本相同的顺序打印出来,但不能阻止错误展示在页面上。其次,在hook中还没有static getDerivedStateFromError和componentDidCatch类似的API。