[BUG] State updates on unmounted components in JsDom
soulfresh opened this issue · comments
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...
- Create a Jest test for a component that uses
useLayer
and has multipleit
statements or nesteddescribe
statements - Run the test a bunch of times
- 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.