74 lines
1.7 KiB
TypeScript
74 lines
1.7 KiB
TypeScript
/** React error boundary that catches render-time exceptions and shows a
|
|
* recoverable error UI instead of a white screen. */
|
|
import * as React from "react";
|
|
|
|
interface Props {
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
interface State {
|
|
error: Error | null;
|
|
}
|
|
|
|
/** Catches uncaught render exceptions in its subtree and displays a message. */
|
|
export class ErrorBoundary extends React.Component<Props, State> {
|
|
constructor(props: Props) {
|
|
super(props);
|
|
this.state = { error: null };
|
|
}
|
|
|
|
static getDerivedStateFromError(error: Error): State {
|
|
return { error };
|
|
}
|
|
|
|
handleReset = () => {
|
|
this.setState({ error: null });
|
|
};
|
|
|
|
render() {
|
|
if (this.state.error) {
|
|
return (
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
height: "100vh",
|
|
background: "#0d1117",
|
|
color: "#e6edf3",
|
|
fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
gap: "16px",
|
|
padding: "32px",
|
|
textAlign: "center",
|
|
}}
|
|
>
|
|
<div style={{ fontSize: "2em" }}>⚠</div>
|
|
<div style={{ fontWeight: 600, fontSize: "1.1em" }}>
|
|
Something went wrong
|
|
</div>
|
|
<div style={{ color: "#8b949e", fontSize: "0.9em", maxWidth: "480px" }}>
|
|
{this.state.error.message}
|
|
</div>
|
|
<button
|
|
type="button"
|
|
onClick={this.handleReset}
|
|
style={{
|
|
padding: "8px 18px",
|
|
borderRadius: "6px",
|
|
border: "1px solid #30363d",
|
|
background: "#21262d",
|
|
color: "#e6edf3",
|
|
cursor: "pointer",
|
|
fontSize: "0.9em",
|
|
}}
|
|
>
|
|
Try again
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|
|
return this.props.children;
|
|
}
|
|
}
|