1import { Component, type ReactNode } from "react";
2
3interface RenderErrorBoundaryProps {
4 readonly children: ReactNode;
5 readonly fallback: ReactNode;
6 readonly resetKeys?: ReadonlyArray<unknown>;
7}
8
9interface RenderErrorBoundaryState {
10 readonly failed: boolean;
11 readonly resetKeys?: ReadonlyArray<unknown> | undefined;
12}
13
14export class RenderErrorBoundary extends Component<
15 RenderErrorBoundaryProps,
16 RenderErrorBoundaryState
17> {
18 override state = { failed: false, resetKeys: this.props.resetKeys };
19
20 // Retry changed inputs without remounting healthy children or their controls.
21 static getDerivedStateFromProps(
22 { resetKeys }: RenderErrorBoundaryProps,
23 state: RenderErrorBoundaryState,
24 ) {
25 if (
26 resetKeys?.length !== state.resetKeys?.length ||
27 resetKeys?.some((key, index) => !Object.is(key, state.resetKeys?.[index]))
28 ) {
29 return { failed: false, resetKeys };
30 }
31 return null;
32 }
33
34 static getDerivedStateFromError() {
35 return { failed: true };
36 }
37
38 override render() {
39 return this.state.failed ? this.props.fallback : this.props.children;
40 }
41}