everweij / react-laag

Hooks to build things like tooltips, dropdown menu's and popovers in React

Home Page:https://www.react-laag.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] State updates on unmounted components in JsDom

soulfresh opened this issue · comments

commented

Describe the bug
I frequently receive warnings from React about updates to unmounted component state when running Jest tests for components that use react-laag. After much debugging, I've narrowed this down to a setState call in useLayer. The issue appears to stem from JsDom's reqestAnimationFrame support but there is a simple solution in this library that you may be willing to accept (see patch below).

The issue seems to be that RAFs can still finish running even after they are cancelled with cancelRequestAnimationFrame. I'm not able to reproduce this issue in a browser so I think it's probably JsDom specific. Since you nullify the raf ref in useLayer on unmount, a super simple fix that may help a lot of your users would be to check that raf.current != null before setting the current layer state in the RAF.

I'm happy to submit a PR for this but wanted to see if you were will to accept the fix in this library even though the underlying issue is probably with JsDom.

To Reproduce
This happens for me in multiple projects when I'm writing tests around useLayer components. It usually goes something like...

  1. Create a Jest test for a component that uses useLayer and has multiple it statements or nested describe statements
  2. Run the test a bunch of times
  3. I'll randomly see unmounted component state update errors from React

Expected behavior
No console errors from React

Browser / OS (please complete the following information):

  • OS: OSX
  • Browser: JsDom
  • Version: jsdom@16.7.0

Additional context
Here is a patch describing the changes I made to fix this issue:

diff --git a/node_modules/react-laag/dist/react-laag.cjs.development.js b/node_modules/react-laag/dist/react-laag.cjs.development.js
index 1919c42..6005a1d 100644
--- a/node_modules/react-laag/dist/react-laag.cjs.development.js
+++ b/node_modules/react-laag/dist/react-laag.cjs.development.js
@@ -2003,8 +2003,22 @@ function useLayer(_ref) {
       }
 
       raf.current = requestAnimationFrame(function () {
-        setState(newState);
-        raf.current = null;
+        // JsDom has an issue where RAFs can run in parallel
+        // to the RAF parent and as a result, cancelRequestAnimationFrame
+        // will not stop an inprocess RAF from runing (at least
+        // that's what appears to happen from my debugging). This
+        // can result in component state being modified even
+        // if the component was unmounted which in turn logs errors
+        // from React about unmounted component state updates. The
+        // simplest solution I can find is to check that `ref.current`
+        // was not nullified in the unmount effect. A more complex
+        // (and potentially more future proof) solution would be to
+        // use a ref to store the unmounted state and check that
+        // here instead.
+        if (raf.current != null ) {
+          setState(newState);
+          raf.current = null;
+        }
       });
     }

Thanks for submitting this issue! This issue should be fixed in the latest release (2.0.4). Feel free to reopen this issue when the problem still occurs.