错误边界(Error boundaries)
从 react v16 开始,引入边界错误概念。
核心 API
getDerivedStateFromError
componentDidCatch
1. 目的:某些 UI 崩溃,不至于整个 webapp 崩溃
2. 注意⚠️:错误边界无法捕获如下场景的错误
- 事件处理(了解更多)
- 异步代码(例如
setTimeout
或requestAnimationFrame
回调函数) - 服务端渲染
- 它自身抛出来的错误(并非它的子组件)
3. 编写错误边界组件
import React, {Component} from 'react';
interface ErrorBoundaryProps { };
interface ErrorBoundaryState {hasError: boolean;};
class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {constructor(props: ErrorBoundaryProps) {super(props);
this.state = {hasError: false};
}
static getDerivedStateFromError(error: Error) {
// 更新 state 使下一次渲染能够显示降级后的 UI
return {hasError: true};
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
// 你同样可以将错误日志上报给服务器
console.group();
console.log('ErrorBoundary catch a error:');
console.info('error', error);
console.info('error info', errorInfo);
console.groupEnd()}
render() {console.log('component ErrorBoundary render...');
const {children} = this.props;
const {hasError} = this.state;
// return (
// <>
// {
// hasError ? 'Something Wrong' : children
// }
// </>
// )
if (hasError) {return 'Something wrong';} else {return children;}
}
}
export default ErrorBoundary;
4. 编写一个“错误组件”
点击按钮,触发 +1,当 counter 为 5 时,抛出 Error
import React, {Component} from 'react';
interface ErrorComponentProps { };
interface ErrorComponentState {counter: number;};
class ErrorComponent extends Component<ErrorComponentProps, ErrorComponentState> {constructor(props: any) {super(props);
this.state = {counter: 0}
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// 事件处理的错误,ErrorBoundary 无法捕捉
// if (this.state.counter === 5) {// throw new Error();
// }
this.setState({counter: this.state.counter + 1});
}
render() {console.log('component ErrorComponent render...');
const {counter} = this.state;
const {handleClick} = this;
if (counter === 5) {throw new Error('counter creashed!');
}
return (
<>
<p>this component will throw Error when the counter equal to 5</p>
<p>counter : {counter}</p>
<button onClick={handleClick}>add</button>
</>
)
}
}
export default ErrorComponent;
5. 组合
import React from 'react';
import ErrorBoundary from './component/ErrorBoundary';
import ErrorComponent from './component/ErrorBoundary/ErrorComponent';
function App() {
return (
<div className="App">
<ErrorBoundary>
<ErrorComponent />
</ErrorBoundary>
</div>
);
}
export default App;
6. 打包静态资源
> 不再 devserver 测试的原因是,在 cra 的配置中,webpack 会捕捉 Error 并显示错误蒙版,不便于看到测试结果
在 package.json 添加字段 "homepage": "."