companion-app: Fehlergrenze um die App - Absturz sichtbar statt schwarzer Seite
Ohne React-Error-Boundary unmountet ein unbehandelter Renderfehler die gesamte App; übrig bleibt nur der Seitenhintergrund (im Nacht-Theme praktisch schwarz) - passt zum gemeldeten "schwarze Seite nach Update prüfen". Behebt nicht die eigentliche Ursache, macht einen künftigen Absturz aber sichtbar (Fehlertext, Neu-laden-Knopf) und loggt ihn in die Konsole statt ihn stumm verschwinden zu lassen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* Auffangnetz für Abstürze irgendwo im Baum.
|
||||||
|
*
|
||||||
|
* Ohne diese Grenze unmountet React die gesamte App bei jedem unbehandelten
|
||||||
|
* Fehler beim Rendern - #wurzel bleibt leer, und übrig bleibt nur der
|
||||||
|
* Seitenhintergrund (im Nacht-Theme praktisch schwarz). Genau das wurde als
|
||||||
|
* "schwarze Seite nach Update prüfen" gemeldet: kein hängender Ladezustand,
|
||||||
|
* sondern ein stiller Absturz, dessen eigentliche Fehlermeldung nirgends
|
||||||
|
* ankam. Ein "zurück und wieder rein" half nur, weil das erneute Öffnen den
|
||||||
|
* Baum komplett neu aufbaut und der auslösende Zustand dabei verschwindet.
|
||||||
|
*
|
||||||
|
* Diese Grenze behebt nicht die eigentliche Ursache - sie sorgt nur dafür,
|
||||||
|
* dass ein Absturz ab jetzt sichtbar ist (Fehlertext, Neu-laden-Knopf) statt
|
||||||
|
* unsichtbar zu bleiben, und dass der Fehlertext in der Konsole landet, um
|
||||||
|
* die eigentliche Ursache beim nächsten Mal fassen zu können.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component, type ReactNode } from "react"
|
||||||
|
|
||||||
|
import { ActionButton } from "@audi-dash/ui"
|
||||||
|
|
||||||
|
export class ErrorGrenze extends Component<
|
||||||
|
{ children: ReactNode },
|
||||||
|
{ fehler: Error | null }
|
||||||
|
> {
|
||||||
|
state: { fehler: Error | null } = { fehler: null }
|
||||||
|
|
||||||
|
static getDerivedStateFromError(fehler: Error) {
|
||||||
|
return { fehler }
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidCatch(fehler: Error, info: { componentStack?: string | null }) {
|
||||||
|
console.error("ErrorGrenze: unbehandelter Fehler beim Rendern", fehler, info.componentStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (!this.state.fehler) return this.props.children
|
||||||
|
return (
|
||||||
|
<div className="dm-leer" style={{ minHeight: "100vh", justifyContent: "center" }}>
|
||||||
|
<span className="dm-leer__titel">Etwas ist schiefgelaufen</span>
|
||||||
|
<p className="dm-leer__text">
|
||||||
|
Die Seite konnte nicht dargestellt werden. Ein Neuladen behebt das in der Regel.
|
||||||
|
</p>
|
||||||
|
<p className="dm-leer__text" style={{ fontFamily: "monospace", fontSize: "12px" }}>
|
||||||
|
{this.state.fehler.message}
|
||||||
|
</p>
|
||||||
|
<ActionButton onClick={() => window.location.reload()}>Neu laden</ActionButton>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import "./stile/grundlage.css"
|
|||||||
import "./stile/audi-schrift.css"
|
import "./stile/audi-schrift.css"
|
||||||
import { nativeAblageEinrichten } from "./api"
|
import { nativeAblageEinrichten } from "./api"
|
||||||
import { App } from "./App"
|
import { App } from "./App"
|
||||||
|
import { ErrorGrenze } from "./ErrorGrenze"
|
||||||
|
|
||||||
// In der nativen Hülle den Token in den Schlüsselbund legen statt in
|
// In der nativen Hülle den Token in den Schlüsselbund legen statt in
|
||||||
// localStorage. Ohne Hülle passiert hier nichts.
|
// localStorage. Ohne Hülle passiert hier nichts.
|
||||||
@@ -16,6 +17,8 @@ if (!wurzel) throw new Error("Wurzelelement #wurzel fehlt in index.html")
|
|||||||
|
|
||||||
createRoot(wurzel).render(
|
createRoot(wurzel).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<App />
|
<ErrorGrenze>
|
||||||
|
<App />
|
||||||
|
</ErrorGrenze>
|
||||||
</StrictMode>,
|
</StrictMode>,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user