negomi / react-burger-menu

:hamburger: An off-canvas sidebar component with a collection of effects and styles using CSS transitions and SVG path animations
http://negomi.github.io/react-burger-menu/
MIT License
5.04k stars 582 forks source link

Timeout with setIsOpen after component unmounted in automated tests #456

Closed lpwprojects closed 2 years ago

lpwprojects commented 2 years ago

Hi, I'm using a simple hamburger menu, which I'm closing when a link is clicked like the followings:

const HamburgerMenu = () => {
  const myContext = useContext(MyContext);
  const {
    isHamburgerMenuOpen,
    toggleHamburgerMenu,
    updateHamburgerMenu,
  } = myContext;

  const handleOnClick = (e) => {
    toggleHamburgerMenu();
  };

  const MenuItem = (props) => (
    <Link onClick={handleOnClick} {...props}>
      {props.children}
    </Link>
  );

  return (
    <Menu isOpen={isHamburgerMenuOpen} onStateChange={updateHamburgerMenu}>
      <MenuItem to="/foo">Foo</MenuItem>
      <MenuItem to="/bar">Bar</MenuItem>
      [...]
    </Menu>
  );
};

I'm experiencing a warning when testing my component using jest (CRA), apparently because of a timeout set state after the test has complete and the component is unmounted...

    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 a useEffect cleanup function.
        at Menu (/[...]/node_modules/react-burger-menu/lib/menuFactory.js:60:46)
        [...]

  at printWarning (node_modules/react-dom/cjs/react-dom.development.js:67:30)
      at error (node_modules/react-dom/cjs/react-dom.development.js:43:5)
      at warnAboutUpdateOnUnmountedFiberInDEV (node_modules/react-dom/cjs/react-dom.development.js:23914:9)
      at scheduleUpdateOnFiber (node_modules/react-dom/cjs/react-dom.development.js:21840:5)
      at dispatchAction (node_modules/react-dom/cjs/react-dom.development.js:16139:5)
      at node_modules/react-burger-menu/lib/menuFactory.js:160:9
      at Timeout.task [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:516:19)

Here's what I have at node_modules/react-burger-menu/lib/menuFactory.js:160:9 : (setIsOpen(...))

    function toggleMenu() {
      var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

      toggleOptions.current = options;

      applyWrapperStyles();

      // Ensures wrapper styles are applied before the menu is toggled
      setTimeout(function () {
        setIsOpen(function (open) {
          return typeof options.isOpen !== 'undefined' ? options.isOpen : !open;
        });
      });
    }

I'm not sure if I'm doing something bad in my setup that triggers this or if the timeout should be removed at some point, but I tried changing it to :

    function toggleMenu() {
      var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

      toggleOptions.current = options;

      applyWrapperStyles();

      // Ensures wrapper styles are applied before the menu is toggled
      //setTimeout(function () {
      //  setIsOpen(function (open) {
      //    return typeof options.isOpen !== 'undefined' ? options.isOpen : !open;
      //  });
      //});
      clearCurrentTimeout();
      timeoutId.current = setTimeout(function () {
        timeoutId.current = null;
        setIsOpen(function (open) {
          return typeof options.isOpen !== 'undefined' ? options.isOpen : !open;
        });
      });
    }

Which seems to work. I want to mention that this happens when I'm using other providers (i18n) performing state changes as well, for some reason, and the problem is not occuring if I use useState hook (and directly perform a set state, instead of using a dispatch in my context via a reducer) in my handleOnClick.

I also found this issue : MenuFactory not clearing timeout when component unmounts #385

Thanks for your feedback

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.