-
-
Notifications
You must be signed in to change notification settings - Fork 480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FormSpy: re-mounting subscription memory leak from render-phase side-effects #411
Comments
Note: this work will also make it React 17+ compliant. I'm also trying to ensure all tests pass as they currently do, and only change / fix what absolutely requires it. EDIT: Didn't realise I had so little free time. Still working on this, and hope to get it PR'd up soon. |
@erikras (re #427 (comment)) Apologies if you took my comment on the PR as an offence/attack - I certainly didn't mean to. Thanks for raising and taking a look, regardless. I'll try to get some time to pick it up again, rebase, etc. |
In the mean time...
|
This should be fixed in |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
1 similar comment
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Are you submitting a bug report or a feature request?
Bug report
What is the current behavior?
The
FormSpy
constructor has a side-effect which, when usingReact.StrictMode
or React async mode, causes a subscription memory leak.React.StrictMode
helps detect unexpected side effects within the render phase by invocating some (most) of the React lifecycle methods twice - this includes theconstructor
. (See here for details/clarification).The
FormSpy
constructor runs the following (here):which in turn runs (here):
hence setting the
this.unsubscribe
class-member variable. Because the constructor is ran twice, the first instantiation'sunsubscribe
value is overwritten, and only the 2nd call's is ever executed incomponentWillUnmount
(here).According to React's docs on async rendering, render phase lifecycles may be invoked more than once, and so
shouldcan not have side-effects.What is the expected behavior?
All render-phase lifecycle methods should be side-effect free, allowing for compatibility with
React.StrictMode
and React async rendering mode.Sandbox Link
https://codesandbox.io/s/n1p24n90xj
It's a little difficult to "show" the issue, but this will do it.
John
->Johna
Doe
->Does
)FormSpy
has re-mounted, hence invocatedcomponentWillUnmount
(commit phase) once and theconstructor
(render phase) twice. One of the original mounting's subscriptions has been retained and not been unsubscribed from during unmounting.The more you re-mount the
FormSpy
, the more subscriptions are left over. Mount it 10 times (so the button says "Mounted 10 times") and you'll see "Values changed" 11 times on every field change (9 stale subscriptions which should have been removed, and 2 new subscriptions).What's your environment?
React.StrictMode
, or any version with async rendering enabled)Other information
Although the codesandbox example is non-real-world, we hit this problem in a real-world scenario where our form expands revealing extra form
Field
s andFormSpy
s.I am more than happy to work on this and PR it, but will obviously needs plenty of review. It will also be a breaking change, as the subscription (and subsequent
onChange
being called) will be moved from theconstructor
tocomponentDidMount
The text was updated successfully, but these errors were encountered: