声明式错误边界Error-Boundary
React ErrorBoundary 类组件实现、生命周期、捕获范围与 Vue 等价方案
#status / evergreen
#tech / dev / component-patterns
#type / concept
声明式错误边界 Error-Boundary
- 核心模式:装饰器模式 (Decorator) / 责任链 (Chain of Responsibility)
- 解构:
- 错误边界就像一个套在外面的保护层(装饰器)。内部
<router-view>正常工作时它透明;一旦抛出异常,异常冒泡(责任链),错误边界捕获并展示友好 UI。
- 错误边界就像一个套在外面的保护层(装饰器)。内部
React ErrorBoundary 实现
ErrorBoundary 必须是 class 组件(截至 React 18,尚无 Hook 版本)。
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
// 渲染阶段调用,更新 state 以展示 fallback UI
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
// 错误报告(日志、监控上报)
componentDidCatch(error, errorInfo) {
console.error('ErrorBoundary caught:', error, errorInfo.componentStack);
// 上报到 Sentry 等监控服务
// reportErrorToService(error, errorInfo);
}
render() {
if (this.state.hasError) {
return this.props.fallback || <h1>出错了</h1>;
}
return this.props.children;
}
}
使用方式:
<ErrorBoundary fallback={<ErrorPage />}>
<RouterView />
</ErrorBoundary>
两个生命周期的区别
| 方法 | 阶段 | 用途 |
|---|---|---|
getDerivedStateFromError | 渲染 | 更新 state 触发 fallback UI 渲染 |
componentDidCatch | 提交 | 副作用:日志记录、错误上报 |
ErrorBoundary 不捕获的场景
以下错误不会被 ErrorBoundary 捕获:
- 事件处理器 — 事件回调中的错误不会冒泡到渲染阶段
- 异步代码 —
setTimeout、Promise、async/await中的错误 - SSR — 服务端渲染期间的错误
- ErrorBoundary 自身的错误 — 不会自我捕获
// 事件处理器:需要用 try-catch 手动处理
function Button() {
const handleClick = () => {
try {
riskyOperation();
} catch (error) {
// 手动处理
}
};
return <button onClick={handleClick}>Click</button>;
}
// 异步:需要全局捕获或 Promise.catch
window.addEventListener('unhandledrejection', (event) => {
console.error('Unhandled rejection:', event.reason);
});
Vue 等价方案
Vue 3 提供 onErrorCaptured 生命周期钩子:
<script setup>
import { onErrorCaptured } from 'vue';
onErrorCaptured((err, instance, info) => {
console.error('捕获到子组件错误:', err);
// 返回 false 阻止错误继续向上传播
return false;
});
</script>
Vue 生态中也有成熟的第三方库:vue-error-boundary、@vue/composables 中的 onErrorCaptured。