/** * Fehlergrenze um den Seiteninhalt. * * Ohne sie reißt ein einziger Fehler in einer Komponente den gesamten Baum ab — * React hängt alles aus, und übrig bleibt eine leere Seite. Im dunklen Thema ist * das ein schwarzer Bildschirm ohne jeden Hinweis, und ein Betreiber hat keine * Möglichkeit zu melden, was schiefging. * * Die Grenze sitzt **um den Inhalt**, nicht um die ganze Anwendung: Seitenleiste * und Kopfzeile bleiben stehen, und man kann auf eine andere Seite wechseln, * statt neu laden zu müssen. * * Klassenkomponente, weil React für Fehlergrenzen keine Entsprechung als Haken * anbietet. */ import { AlertTriangle } from 'lucide-react'; import { Component, type ErrorInfo, type ReactNode } from 'react'; import { Button } from '@/components/ui'; interface ErrorBoundaryProps { /** Wechselt der Wert, wird der Fehler verworfen — etwa beim Seitenwechsel. */ readonly resetKey: string; readonly children: ReactNode; } interface ErrorBoundaryState { readonly caughtError: Error | null; readonly componentStack: string; readonly resetKey: string; } export class ErrorBoundary extends Component { public constructor(properties: ErrorBoundaryProps) { super(properties); this.state = { caughtError: null, componentStack: '', resetKey: properties.resetKey }; } public static getDerivedStateFromError(caughtError: Error): Partial { return { caughtError }; } /** * Verwirft den Fehler beim Seitenwechsel. * * Abgeleitet statt in einem Effekt gesetzt: Sonst zeigte die neue Seite noch * einen Wimpernschlag lang den Fehler der alten. */ public static getDerivedStateFromProps( nextProperties: ErrorBoundaryProps, currentState: ErrorBoundaryState, ): Partial | null { if (nextProperties.resetKey !== currentState.resetKey) { return { caughtError: null, componentStack: '', resetKey: nextProperties.resetKey }; } return null; } public override componentDidCatch(caughtError: Error, errorInfo: ErrorInfo): void { this.setState({ componentStack: errorInfo.componentStack ?? '' }); // Die Meldung gehört in die Entwicklerkonsole, damit sie sich kopieren // lässt. Sie hier zu verschlucken wäre der stille Fehler, den die // Entwicklungsregeln ausdrücklich verbieten. console.error('Unbehandelter Fehler in der Oberfläche:', caughtError, errorInfo); } public override render(): ReactNode { const { caughtError, componentStack } = this.state; if (caughtError === null) { return this.props.children; } return (

Diese Seite konnte nicht angezeigt werden

Die übrige Konsole arbeitet weiter. Wechseln Sie den Bereich oder laden Sie neu.

              {caughtError.message || caughtError.name}
              {componentStack ? `\n${componentStack.trim().split('\n').slice(0, 6).join('\n')}` : ''}
            
); } }