aboutsummaryrefslogtreecommitdiff
path: root/src/components/ErrorBoundary.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/ErrorBoundary.tsx')
-rw-r--r--src/components/ErrorBoundary.tsx128
1 files changed, 68 insertions, 60 deletions
diff --git a/src/components/ErrorBoundary.tsx b/src/components/ErrorBoundary.tsx
index ed565c5..aa1e889 100644
--- a/src/components/ErrorBoundary.tsx
+++ b/src/components/ErrorBoundary.tsx
@@ -16,6 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+import { LazyComponent } from "../utils";
import Logger from "../utils/logger";
import { Margins, React } from "../webpack/common";
import { ErrorCard } from "./ErrorCard";
@@ -32,68 +33,75 @@ const logger = new Logger("React ErrorBoundary", color);
const NO_ERROR = {};
-export default class ErrorBoundary extends React.Component<React.PropsWithChildren<Props>> {
- static wrap<T = any>(Component: React.ComponentType<T>): (props: T) => React.ReactElement {
- return props => (
- <ErrorBoundary>
- <Component {...props as any/* I hate react typings ??? */} />
- </ErrorBoundary>
- );
- }
-
- state = {
- error: NO_ERROR as any,
- stack: "",
- message: ""
- };
+// We might want to import this in a place where React isn't ready yet.
+// Thus, wrap in a LazyComponent
+const ErrorBoundary = LazyComponent(() => {
+ return class ErrorBoundary extends React.PureComponent<React.PropsWithChildren<Props>> {
+ state = {
+ error: NO_ERROR as any,
+ stack: "",
+ message: ""
+ };
- static getDerivedStateFromError(error: any) {
- let stack = error?.stack ?? "";
- let message = error?.message || String(error);
+ static getDerivedStateFromError(error: any) {
+ let stack = error?.stack ?? "";
+ let message = error?.message || String(error);
- if (error instanceof Error && stack) {
- const eolIdx = stack.indexOf("\n");
- if (eolIdx !== -1) {
- message = stack.slice(0, eolIdx);
- stack = stack.slice(eolIdx + 1).replace(/https:\/\/\S+\/assets\//g, "");
+ if (error instanceof Error && stack) {
+ const eolIdx = stack.indexOf("\n");
+ if (eolIdx !== -1) {
+ message = stack.slice(0, eolIdx);
+ stack = stack.slice(eolIdx + 1).replace(/https:\/\/\S+\/assets\//g, "");
+ }
}
+
+ return { error, stack, message };
}
- return { error, stack, message };
- }
-
- componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
- this.props.onError?.(error, errorInfo);
- logger.error("A component threw an Error\n", error);
- logger.error("Component Stack", errorInfo.componentStack);
- }
-
- render() {
- if (this.state.error === NO_ERROR) return this.props.children;
-
- if (this.props.fallback)
- return <this.props.fallback
- children={this.props.children}
- {...this.state}
- />;
-
- const msg = this.props.message || "An error occurred while rendering this Component. More info can be found below and in your console.";
-
- return (
- <ErrorCard style={{
- overflow: "hidden",
- }}>
- <h1>Oh no!</h1>
- <p>{msg}</p>
- <code>
- {this.state.message}
- {!!this.state.stack && (
- <pre className={Margins.marginTop8}>
- {this.state.stack}
- </pre>
- )}
- </code>
- </ErrorCard>
- );
- }
-}
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
+ this.props.onError?.(error, errorInfo);
+ logger.error("A component threw an Error\n", error);
+ logger.error("Component Stack", errorInfo.componentStack);
+ }
+
+ render() {
+ if (this.state.error === NO_ERROR) return this.props.children;
+
+ if (this.props.fallback)
+ return <this.props.fallback
+ children={this.props.children}
+ {...this.state}
+ />;
+
+ const msg = this.props.message || "An error occurred while rendering this Component. More info can be found below and in your console.";
+
+ return (
+ <ErrorCard style={{
+ overflow: "hidden",
+ }}>
+ <h1>Oh no!</h1>
+ <p>{msg}</p>
+ <code>
+ {this.state.message}
+ {!!this.state.stack && (
+ <pre className={Margins.marginTop8}>
+ {this.state.stack}
+ </pre>
+ )}
+ </code>
+ </ErrorCard>
+ );
+ }
+ };
+}) as
+ React.ComponentType<React.PropsWithChildren<Props>> & {
+ wrap<T extends JSX.IntrinsicAttributes = any>(Component: React.ComponentType<T>): React.ComponentType<T>;
+ };
+
+ErrorBoundary.wrap = Component => props => (
+ <ErrorBoundary>
+ <Component {...props} />
+ </ErrorBoundary>
+);
+
+export default ErrorBoundary;