Description
Summary:
A recent change to fix css transitions in Safari seems to have created the potential for a race condition (or memory leak as the React warning points out). The relevant state change was moved into a requestAnimationFrame
callback, but there is no guarantee that the component will still be mounted by the time the callback executes. The error message I am seeing is:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
ModalPortal@https://f02nn.csb.app/node_modules/react-modal/lib/components/ModalPortal.js:70:20
Modal@https://f02nn.csb.app/node_modules/react-modal/lib/components/Modal.js:73:20
(Note I have removed the rest of the stack as it contains references to closed-source code).
Steps to reproduce:
So far I have only been able to reproduce this issue using tests, which is where I first encountered the issue. A simple test to open and close the modal triggers the warning, though the test does not fail:
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import "@testing-library/jest-dom";
import Modal from "react-modal";
import App from "./App";
it("Opens and closes the modal", () => {
const { container } = render(<App />);
Modal.setAppElement(container);
userEvent.click(screen.getByText("Open"));
expect(screen.getByRole("dialog")).toBeInTheDocument();
userEvent.click(screen.getByText("Close"));
expect(screen.queryByRole("dialog")).toBeNull();
});
I have created a codesandbox to illustrate the issue (see below). Note that with codesandbox the console error for the tests will appear in the "Browser" tab, not the "Tests" tab for some reason.
Screen.Recording.2021-06-03.at.1.17.08.PM.mov
Expected behavior:
The warning does not appear.
Link to example of issue:
https://codesandbox.io/s/react-modal-memory-leak-f02nn
Additional notes:
One solution might be to add an isMounted
check to the requestAnimationFrame
callback. If I have more time later I can try adding that check.