Skip to content

Commit 943a0c6

Browse files
committed
Bugfix: Render context around fallback UI so useErrorBoundary works inside of fallback
1 parent c5b03ea commit 943a0c6

File tree

3 files changed

+44
-9
lines changed

3 files changed

+44
-9
lines changed

src/ErrorBoundary.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ import {
66
PropsWithChildren,
77
PropsWithRef,
88
} from "react";
9-
import {
10-
ErrorBoundaryContextType,
11-
ErrorBoundaryContext,
12-
} from "./ErrorBoundaryContext";
9+
import { ErrorBoundaryContext } from "./ErrorBoundaryContext";
1310
import { ErrorBoundaryProps, FallbackProps } from "./types";
1411

1512
type ErrorBoundaryState = { didCatch: boolean; error: any };
@@ -78,18 +75,20 @@ export class ErrorBoundary extends Component<
7875
this.props;
7976
const { didCatch, error } = this.state;
8077

78+
let childToRender = children;
79+
8180
if (didCatch) {
8281
const props: FallbackProps = {
8382
error,
8483
resetErrorBoundary: this.resetErrorBoundary,
8584
};
8685

8786
if (isValidElement(fallback)) {
88-
return fallback;
87+
childToRender = fallback;
8988
} else if (typeof fallbackRender === "function") {
90-
return fallbackRender(props);
89+
childToRender = fallbackRender(props);
9190
} else if (FallbackComponent) {
92-
return createElement(FallbackComponent, props);
91+
childToRender = createElement(FallbackComponent, props);
9392
} else {
9493
throw new Error(
9594
"react-error-boundary requires either a fallback, fallbackRender, or FallbackComponent prop"
@@ -106,7 +105,7 @@ export class ErrorBoundary extends Component<
106105
resetErrorBoundary: this.resetErrorBoundary,
107106
},
108107
},
109-
children
108+
childToRender
110109
);
111110
}
112111
}

src/ErrorBoundaryContext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createContext } from "react";
22

33
export type ErrorBoundaryContextType = {
4-
didCatch: false;
4+
didCatch: boolean;
55
error: any;
66
resetErrorBoundary: (...args: any[]) => void;
77
};

src/useErrorBoundary.test.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,40 @@ describe("useErrorBoundary", () => {
6262
});
6363
expect(container.textContent).toBe("Child");
6464
});
65+
66+
it("should work within a fallback component", () => {
67+
let resetBoundary: UseErrorBoundaryApi<Error>["resetBoundary"] | null =
68+
null;
69+
let showBoundary: UseErrorBoundaryApi<Error>["showBoundary"] | null = null;
70+
71+
function FallbackComponent() {
72+
resetBoundary = useErrorBoundary<Error>().resetBoundary;
73+
return <div>Error</div>;
74+
}
75+
76+
function Child() {
77+
showBoundary = useErrorBoundary<Error>().showBoundary;
78+
return <div>Child</div>;
79+
}
80+
81+
const root = createRoot(container);
82+
act(() => {
83+
root.render(
84+
<ErrorBoundary FallbackComponent={FallbackComponent}>
85+
<Child />
86+
</ErrorBoundary>
87+
);
88+
});
89+
expect(container.textContent).toBe("Child");
90+
91+
act(() => {
92+
showBoundary!(new Error("Example"));
93+
});
94+
expect(container.textContent).toBe("Error");
95+
96+
act(() => {
97+
resetBoundary!();
98+
});
99+
expect(container.textContent).toBe("Child");
100+
});
65101
});

0 commit comments

Comments
 (0)