fix(app): add ErrorBoundary to show actual crash errors instead of white screen

This commit is contained in:
Haze
2026-02-06 03:48:29 +08:00
Unverified
parent 7818798bff
commit 7089c7a891

View File

@@ -3,7 +3,8 @@
* Handles routing and global providers
*/
import { Routes, Route, useNavigate, useLocation } from 'react-router-dom';
import { useEffect } from 'react';
import { Component, useEffect } from 'react';
import type { ErrorInfo, ReactNode } from 'react';
import { Toaster } from 'sonner';
import { MainLayout } from './components/layout/MainLayout';
import { Dashboard } from './pages/Dashboard';
@@ -16,6 +17,70 @@ import { Setup } from './pages/Setup';
import { useSettingsStore } from './stores/settings';
import { useGatewayStore } from './stores/gateway';
/**
* Error Boundary to catch and display React rendering errors
*/
class ErrorBoundary extends Component<
{ children: ReactNode },
{ hasError: boolean; error: Error | null }
> {
constructor(props: { children: ReactNode }) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}
componentDidCatch(error: Error, info: ErrorInfo) {
console.error('React Error Boundary caught error:', error, info);
}
render() {
if (this.state.hasError) {
return (
<div style={{
padding: '40px',
color: '#f87171',
background: '#0f172a',
minHeight: '100vh',
fontFamily: 'monospace'
}}>
<h1 style={{ fontSize: '24px', marginBottom: '16px' }}>Something went wrong</h1>
<pre style={{
whiteSpace: 'pre-wrap',
wordBreak: 'break-all',
background: '#1e293b',
padding: '16px',
borderRadius: '8px',
fontSize: '14px'
}}>
{this.state.error?.message}
{'\n\n'}
{this.state.error?.stack}
</pre>
<button
onClick={() => { this.setState({ hasError: false, error: null }); window.location.reload(); }}
style={{
marginTop: '16px',
padding: '8px 16px',
background: '#3b82f6',
color: 'white',
border: 'none',
borderRadius: '6px',
cursor: 'pointer'
}}
>
Reload
</button>
</div>
);
}
return this.props.children;
}
}
function App() {
const navigate = useNavigate();
const location = useLocation();
@@ -69,7 +134,7 @@ function App() {
}, [theme]);
return (
<>
<ErrorBoundary>
<Routes>
{/* Setup wizard (shown on first launch) */}
<Route path="/setup/*" element={<Setup />} />
@@ -91,7 +156,7 @@ function App() {
richColors
closeButton
/>
</>
</ErrorBoundary>
);
}