|
1 |
| -import * as React from "react"; |
| 1 | +import React, { useState, useEffect, FC } from "react"; |
| 2 | +import { useLocation } from "react-router-dom"; |
2 | 3 | import Page from "./Page";
|
3 | 4 |
|
4 |
| -export default class ErrorBoundary extends React.Component< |
5 |
| - any, |
6 |
| - { hasError: boolean; error: Error } |
7 |
| -> { |
8 |
| - constructor(props) { |
| 5 | +interface Props { |
| 6 | + hasError: boolean; |
| 7 | + error: Error | null; |
| 8 | +} |
| 9 | + |
| 10 | +class ErrorBoundaryDetail extends React.Component<any, Props> { |
| 11 | + constructor(props: any) { |
9 | 12 | super(props);
|
10 | 13 | this.state = { hasError: false, error: null };
|
11 | 14 | }
|
12 | 15 |
|
13 |
| - static getDerivedStateFromError(error) { |
14 |
| - // Update state so the next render will show the fallback UI. |
| 16 | + static getDerivedStateFromError(error: Error) { |
15 | 17 | return { hasError: true, error };
|
16 | 18 | }
|
17 | 19 |
|
18 |
| - componentDidCatch(error) { |
19 |
| - // You can also log the error to an error reporting service |
| 20 | + componentDidUpdate(prevProps: Props) { |
| 21 | + if (!this.props.hasError && prevProps.hasError) { |
| 22 | + this.setState({ hasError: false }); |
| 23 | + } |
| 24 | + } |
| 25 | + |
| 26 | + componentDidCatch(error: Error) { |
20 | 27 | console.error(error);
|
| 28 | + this.props.setHasError(true); |
21 | 29 | }
|
22 | 30 |
|
23 | 31 | render() {
|
24 | 32 | if (this.state.hasError) {
|
25 |
| - // You can render any custom fallback UI |
26 | 33 | return (
|
27 | 34 | <Page>
|
28 | 35 | <h3>Something went wrong.</h3>
|
29 |
| - <pre>{this.state.error.message}</pre> |
30 |
| - <pre>{this.state.error.stack}</pre> |
| 36 | + <pre>{this.state.error?.message}</pre> |
| 37 | + <pre>{this.state.error?.stack}</pre> |
31 | 38 | </Page>
|
32 | 39 | );
|
33 | 40 | }
|
34 | 41 |
|
35 | 42 | return this.props.children;
|
36 | 43 | }
|
37 | 44 | }
|
| 45 | + |
| 46 | +/** Function component wrapper as we need useEffect to set the state back to false on location changing **/ |
| 47 | +const ErrorBoundary: FC<{ children: React.ReactNode }> = ({ children }) => { |
| 48 | + const [hasError, setHasError] = useState<boolean>(false); |
| 49 | + const location = useLocation(); |
| 50 | + |
| 51 | + useEffect(() => { |
| 52 | + if (hasError) { |
| 53 | + setHasError(false); |
| 54 | + } |
| 55 | + }, [location.key]); |
| 56 | + |
| 57 | + return ( |
| 58 | + <ErrorBoundaryDetail hasError={hasError} setHasError={setHasError}> |
| 59 | + {children} |
| 60 | + </ErrorBoundaryDetail> |
| 61 | + ); |
| 62 | +}; |
| 63 | + |
| 64 | +export default ErrorBoundary; |
0 commit comments