| 37 | // This is forked from error-boundary. |
| 38 | // TODO: Extend it instead of forking to easily sync the behavior? |
| 39 | class CatchError<P extends UserProps> extends React.Component< |
| 40 | CatchErrorProps<P>, |
| 41 | { error: Error | null; previousPathname: string | null } |
| 42 | > { |
| 43 | declare context: AppRouterInstance | null |
| 44 | static contextType = AppRouterContext |
| 45 | // `unstable_catchError()` is parsed as an HOC-style name and displays as |
| 46 | // a label (<name> [unstable_catchError]) in DevTools. |
| 47 | static displayName = 'unstable_catchError(Next.CatchError)' |
| 48 | |
| 49 | constructor(props: CatchErrorProps<P>) { |
| 50 | super(props) |
| 51 | this.state = { |
| 52 | error: null, |
| 53 | previousPathname: this.props.pathname, |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | static getDerivedStateFromError(error: Error) { |
| 58 | if (isNextRouterError(error)) { |
| 59 | // Re-throw if an expected internal Next.js router error occurs |
| 60 | // this means it should be handled by a different boundary (such as a NotFound boundary in a parent segment) |
| 61 | throw error |
| 62 | } |
| 63 | |
| 64 | return { error } |
| 65 | } |
| 66 | |
| 67 | static getDerivedStateFromProps( |
| 68 | props: CatchErrorProps<UserProps>, |
| 69 | state: CatchErrorState |
| 70 | ): CatchErrorState | null { |
| 71 | const { error } = state |
| 72 | |
| 73 | // if we encounter an error while |
| 74 | // a navigation is pending we shouldn't render |
| 75 | // the error boundary and instead should fallback |
| 76 | // to a hard navigation to attempt recovering |
| 77 | if (process.env.__NEXT_APP_NAV_FAIL_HANDLING) { |
| 78 | if (error && handleHardNavError(error)) { |
| 79 | // clear error so we don't render anything |
| 80 | return { |
| 81 | error: null, |
| 82 | previousPathname: props.pathname, |
| 83 | } |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | /** |
| 88 | * Handles reset of the error boundary when a navigation happens. |
| 89 | * Ensures the error boundary does not stay enabled when navigating to a new page. |
| 90 | * Approach of setState in render is safe as it checks the previous pathname and then overrides |
| 91 | * it as outlined in https://react.dev/reference/react/useState#storing-information-from-previous-renders |
| 92 | */ |
| 93 | if (props.pathname !== state.previousPathname && state.error) { |
| 94 | return { |
| 95 | error: null, |
| 96 | previousPathname: props.pathname, |
nothing calls this directly
no test coverage detected