React Error Boundary在函数组件里为什么没捕获错误?
我用类组件做Error Boundary包裹了一个函数组件,但函数组件里useEffect抛出的错误没被捕获,控制台直接显示未处理的 rejection。componentDidCatch明明写了却没触发,这是怎么回事?
代码是这样的:class ErrorBoundary extends React.Component { componentDidCatch() { console.log('这里没执行!') }}
函数组件里这样写:
function MyComponent() {
useEffect(() => {
setTimeout(() => {
throw new Error('测试错误')
}, 1000);
}, []);
return <div>测试内容</div>
}
换成类组件写法就能捕获,但函数组件总是直接报错,是不是哪里配置错了?
React 的 Error Boundary 不会捕获以下几类错误:
- 异步代码里的错误(比如 setTimeout、Promise.then、事件回调)
- 事件处理器中的错误
- 服务端渲染时的错误
- 自身抛出的错误(即 Error Boundary 组件自己出错)
你在 useEffect 里 setTimeout 抛错,等同于在事件循环的 macro task 中扔了个异常,这时候组件早就渲染完了,Error Boundary 已经不在“监控状态”。
解决办法有两个:
第一种是把错误主动交给 React 处理,比如用一个状态来模拟崩溃:
这样你在函数组件里手动 throw,就会被外层 Error Boundary 捕获。
第二种更实际的做法是在异步中做自己的错误处理,别指望 Error Boundary 能帮你兜底所有错误。比如加个 try-catch 后上报错误或降级 UI。
总结:不是函数组件的问题,而是异步错误本来就不归 Error Boundary 管。换成类组件也一样捕获不到,除非你也在 componentDidMount 里写 setTimeout 抛错。浏览器兼容性倒没问题,这是设计机制问题,不是兼容性 bug。