From a5b9835b1ecf61b51557f5ba2b71d4196abd9e54 Mon Sep 17 00:00:00 2001 From: Dominik Horn Date: Thu, 27 Feb 2020 17:28:06 +0100 Subject: [PATCH] implement ErrorBoundary component #15 --- .../src/components/general/ErrorBoundary.tsx | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 packages/frontend/src/components/general/ErrorBoundary.tsx diff --git a/packages/frontend/src/components/general/ErrorBoundary.tsx b/packages/frontend/src/components/general/ErrorBoundary.tsx new file mode 100644 index 0000000..eee30d0 --- /dev/null +++ b/packages/frontend/src/components/general/ErrorBoundary.tsx @@ -0,0 +1,71 @@ +import * as React from 'react'; + +/** + * Properties of Error Boundary + */ +export interface ErrorBoundaryProps { + /** + * Callback used to render ui for the error once it occured + */ + readonly errorRenderer?: (error: Error) => React.ReactNode; +} + +interface State { + readonly error?: Error; +} + +function renderError(error: Error): React.ReactNode { + return error.message; +} + +/** + * ErrorBoundary component catches all errors that occur somewhere bellow in the DOM + * tree and displays an error message instead of taking the entire page down. + * + * Use by wrapping it around failable components in JSX + * or use the withErrorBoundary(...) to wrap component components + */ +export class ErrorBoundary extends React.Component { + constructor(props: ErrorBoundaryProps) { + super(props); + this.state = {}; + } + + static getDerivedStateFromError(error: Error) { + return { error }; + } + + componentDidCatch(error: Error, info: React.ErrorInfo) { + console.error('Caught error:', error, 'with info:', info); + console.trace(); + } + + render() { + const { error } = this.state; + if (error) { + return renderError(error); + } + return <>{this.props.children}; + } +} + +/** + * ErrorBoundary component catches all errors that occur somewhere bellow in the DOM + * tree and displays an error message instead of taking the entire page down. + * + * Use by wrapping it around failable components in JSX, i.e., ... + * or using this component wrapper + * + * @param WrappedComponent component to wrap + * @param errorRenderer callback to render error ui + */ +export function withErrorBoundary( + WrappedComponent: React.ComponentType, + errorRenderer: (error: Error) => React.ReactNode = renderError, +): React.ComponentType { + return (props: TProps) => ( + + + + ); +}