为什么Error Boundary没捕获到setTimeout里的错误?
我在组件里用类组件做Error Boundary包裹了子组件,但子组件useEffect里的setTimeout里抛错后,页面直接崩溃了,componentDidCatch没触发,这是怎么回事?
代码是这样的:class ErrorBoundary extends React.Component { componentDidCatch() { console.log('捕获到错误') } } 然后在子组件用:
useEffect(() => {
setTimeout(() => {
throw new Error('测试异步错误')
}, 1000)
}, [])
我已经确认Boundary是类组件且写了状态保存错误,但控制台只显示Uncaught Error,没触发Boundary的方法,是不是哪里用错了?
解决方法是要么把错误处理移到setTimeout内部,要么用window.onerror全局捕获。给你两个方案:
方案1:在setTimeout里自己try catch
方案2:全局错误监听
说白了Error Boundary就是个装饰器模式实现,异步错误已经跑到事件循环里了,Boundary自然抓不到。这问题我也踩过坑,后来看React源码才明白的。
想让 Error Boundary 捕获到异步错误,得把错误抛到 React 能追踪到的上下文里。你可以优化一下写法,用 unstable_noStoreYet 或者 componentDidCatch 的能力来包裹异步操作,或者手动把错误抛到组件生命周期里。
比如你现在的类组件 ErrorBoundary 已经写了 componentDidCatch,但你在 setTimeout 里 throw 的错误,React 拿不到上下文,只能变成全局未捕获错误。
想修复的话,可以改成这样:
或者在 componentDidCatch 之外再监听 window.onerror,做兜底处理。
说到底,Error Boundary 不是用来处理所有异步错误的,它只是 React 组件树内的错误捕获机制,想真正覆盖异步错误,还得结合全局错误监听和 Promise 链路追踪。