这套组合的骨架你说全了,我补几个实战里最容易踩的点,尤其是 React.lazy 那部分。

边界抓不到的东西要提前心里有数:事件处理函数里的报错、setTimeout/Promise 的异步回调、SSR、以及边界组件自身 render 抛的错,一律漏过去。所以像 onClick 里的请求失败,别指望边界兜底,得自己 try/catch 或走请求层的统一错误处理。

懒加载失败的坑比组件崩溃更常见:发版后旧的 chunk hash 变了,用户手里的页面再触发 import() 必然 404,这时候边界虽然能显示降级 UI,但用户点「重试」还是失败。标准做法是识别出 Failed to fetch dynamically imported module 这类错误,降级 UI 里直接给一个「刷新页面」按钮,或者在 lazy 外面包一层带重试次数的 loader。你贴的代码在这里截断了,Suspense 的 fallback 建议给个带 min-height 的骨架,避免加载完成后页面高度跳变。

reset 的粒度:key={location.pathname} 这个写法确实省事,但要注意它会把子树整个卸载重挂、状态全丢。如果只是想在 props 变化时清错误,用 resetKeys(自己实现一个 componentDidUpdate 比对数组即可)更温和。

React 18+ 的补充:createRoot 现在支持 onCaughtError / onUncaughtError,可以当全局兜底打点,和边界不冲突。另外真要省事可以直接用 react-error-boundary,它把 resetKeys、onReset、useErrorBoundary 都封装好了,自己维护边界类容易漏细节。

顺带提一句,React 19 里 use() 配合 Suspense 时,Promise reject 也是抛给最近的错误边界的,所以两块拼图的边界层级顺序是 Suspense 在内、ErrorBoundary 在外,别搞反。