diff --git a/src/components/EmbeddedCheckout.client.test.tsx b/src/components/EmbeddedCheckout.client.test.tsx index 0ac2b45..a6749bd 100644 --- a/src/components/EmbeddedCheckout.client.test.tsx +++ b/src/components/EmbeddedCheckout.client.test.tsx @@ -129,4 +129,29 @@ describe('EmbeddedCheckout on the client', () => { ); expect(mockEmbeddedCheckout.unmount).toBeCalled(); }); + + it('does not throw when the Embedded Checkout instance is already destroyed when unmounting', async () => { + const {container, rerender} = render( + + + + ); + + await act(() => mockEmbeddedCheckoutPromise); + + expect(mockEmbeddedCheckout.mount).toBeCalledWith(container.firstChild); + + mockEmbeddedCheckout.unmount.mockImplementation(() => { + throw new Error('instance has been destroyed'); + }); + + expect(() => { + rerender( + + ); + }).not.toThrow(); + }); }); diff --git a/src/components/EmbeddedCheckout.tsx b/src/components/EmbeddedCheckout.tsx index cf0db84..337aadc 100644 --- a/src/components/EmbeddedCheckout.tsx +++ b/src/components/EmbeddedCheckout.tsx @@ -32,8 +32,17 @@ const EmbeddedCheckoutClientElement = ({ // Clean up on unmount return () => { if (isMounted.current && embeddedCheckout) { - embeddedCheckout.unmount(); - isMounted.current = false; + try { + embeddedCheckout.unmount(); + isMounted.current = false; + } catch (e) { + // Do nothing. + // Parent effects are destroyed before child effects, so + // in cases where both the EmbeddedCheckoutProvider and + // the EmbeddedCheckout component are removed at the same + // time, the embeddedCheckout instance will be destroyed, + // which causes an error when calling unmount. + } } }; }, [embeddedCheckout]);