Skip to content

Commit

Permalink
Merge pull request #18 from elite-se/feature/error-boundary
Browse files Browse the repository at this point in the history
Feature/error boundary
  • Loading branch information
toschmidt authored Feb 27, 2020
2 parents 96e3a62 + b403f1e commit 65c59c4
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 1 deletion.
5 changes: 4 additions & 1 deletion packages/frontend/src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { hot } from 'react-hot-loader';
import { Redirect, Route, Switch } from 'react-router';
import { Router } from 'react-router-dom';
import history from '../util/history';
import { ErrorBoundary } from './general/ErrorBoundary';
import { AppPath, APP_ROUTES } from '../util/routes';

// Global bootstrap: install subsystems and load configuration
Expand All @@ -16,7 +17,9 @@ export const AppComponent = () => (
<Router history={history}>
<Switch>
{APP_ROUTES.map((routeProps, index) => (
<Route key={index} {...routeProps} />
<ErrorBoundary>
<Route key={index} {...routeProps} />
</ErrorBoundary>
))}
{/* Error 404 Fallback */}
<Redirect to={AppPath.HOME} />
Expand Down
71 changes: 71 additions & 0 deletions packages/frontend/src/components/general/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -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<ErrorBoundaryProps, State> {
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., <ErrorBoundary>...</ErrorBoundary>
* or using this component wrapper
*
* @param WrappedComponent component to wrap
* @param errorRenderer callback to render error ui
*/
export function withErrorBoundary<TProps>(
WrappedComponent: React.ComponentType<TProps>,
errorRenderer: (error: Error) => React.ReactNode = renderError,
): React.ComponentType<TProps> {
return (props: TProps) => (
<ErrorBoundary errorRenderer={errorRenderer}>
<WrappedComponent {...props} />
</ErrorBoundary>
);
}

0 comments on commit 65c59c4

Please sign in to comment.