如何统一监听react组件报错
面试速答
- 以下内容以 React 18 为准。
- “统一监听 React 报错”不能只靠一种手段,通常要分成三层:
- React 渲染错误:
ErrorBoundary - 全局运行时错误:
window.onerror - 异步错误:
unhandledrejection
- React 渲染错误:
- React 18 里如果使用
createRoot,还可以关注onRecoverableError。
第一层:组件树渲染错误
最核心的是错误边界 ErrorBoundary。
它能捕获后代组件中的:
- render 报错
- 生命周期报错
- 构造函数报错
典型写法:
class AppErrorBoundary extends React.Component<
{children: React.ReactNode},
{hasError: boolean}
> {
state = {hasError: false}
static getDerivedStateFromError() {
return {hasError: true}
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
reportError({
error,
componentStack: info.componentStack,
})
}
render() {
if (this.state.hasError) return <div>页面异常</div>
return this.props.children
}
}
第二层:全局脚本错误
有些错误不在 React 渲染链路里,比如:
- 第三方脚本异常
- 手写原生事件回调异常
- 资源加载错误
这时可以补:
window.addEventListener('error', event => {
reportError({type: 'error', event})
})
第三层:Promise 未处理异常
很多请求链路、异步逻辑会以 Promise 失败形式出现:
window.addEventListener('unhandledrejection', event => {
reportError({type: 'unhandledrejection', reason: event.reason})
})
React 18 的补充点
如果使用:
createRoot(container, {
onRecoverableError(error) {
reportError({type: 'recoverable', error})
},
})
可以监听一些可恢复错误,尤其在 hydration 等场景里有价值。
统一上报时要带什么
至少建议带:
- 错误消息
- 堆栈信息
componentStack- 当前路由
- 用户信息或会话标识
- 构建版本号
这样排查才真正有意义。
边界要讲清
ErrorBoundary 捕获不到:
- 事件处理函数里的异常
setTimeout里的异常- Promise 异步链未捕获异常
- 服务端渲染阶段异常
所以它只能覆盖“组件渲染树的一部分错误”,不是万能兜底。
标准答法
问:如何统一监听 React 组件报错?
答:一般是 ErrorBoundary + window.onerror + unhandledrejection + 日志上报平台 的组合。React 18 如果是 createRoot,还可以补 onRecoverableError。
易错点
- 误以为
ErrorBoundary能抓到所有异常。 - 只采集错误消息,不带组件栈和版本信息。
- 线上报错后没有降级 UI,用户直接白屏。
速记要点
- 渲染错误靠
ErrorBoundary。 - 全局脚本错误靠
error。 - 异步 Promise 错误靠
unhandledrejection。