-
Notifications
You must be signed in to change notification settings - Fork 96
Prevent setting state on unmounted withOnyx components #120
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -358,6 +358,12 @@ function keyChanged(key, data) { | |
| * @param {String} key | ||
| */ | ||
| function sendDataToConnection(config, val, key) { | ||
| // If the mapping no longer exists then we should not send any data. | ||
| // This means our subscriber disconnected or withOnyx wrapped component unmounted. | ||
| if (!callbackToStateMapping[config.connectionID]) { | ||
| return; | ||
| } | ||
|
|
||
| if (config.withOnyxInstance) { | ||
| config.withOnyxInstance.setWithOnyxState(config.statePropertyName, val); | ||
| } else if (_.isFunction(config.callback)) { | ||
|
|
@@ -388,6 +394,7 @@ function sendDataToConnection(config, val, key) { | |
| function connect(mapping) { | ||
| const connectionID = lastConnectionID++; | ||
| callbackToStateMapping[connectionID] = mapping; | ||
| callbackToStateMapping[connectionID].connectionID = connectionID; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to give the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, so since we do
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good overview here: https://eloquentjavascript.net/04_data.html#h_C3n45IkMhg
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mutating input parameters is considered a bad practice, some more strict languages would not even allow it const privateMapping = {
...mapping,
connectionID,
};
callbackToStateMapping[connectionID] = privateMapping;Also because of referential equality it should be possible to achieve the same without capturing // If the mapping no longer exists then we should not send any data.
// This means our subscriber disconnected or withOnyx wrapped component unmounted.
if (_.every(callbackToStateMapping(mapping => mapping !== config)) {
return;
}
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is it considered a bad practice and what kinds of problems do you think it can cause? We are not accessing the connection mapping besides internally once it is passed here so I did not worry about mutations in this case.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For this particular usage primarily confusion
In particular for mutating input arguments:
small airbnb thread on the subject of param reasinging: airbnb/javascript#641 In general:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree it depends on the context/case, but not sure if I agree there is anything inherently confusing about this. I might not be understanding the full argument about why this is "bad" or what the unexpected behavior would be in this case. Confusion is subjective. Someone could be equally confused about why we are using the spread syntax or checking for equality on an object reference (not very obvious IMO). I'm not convinced there's anything we need to do here, but do appreciate the thoughts.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Less confusing way with mutation: const connectionID = lastConnectionID++;
mapping.connectionID = connectionID;
callbackToStateMapping[connectionID] = mapping;This also makes the mutation obvious
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noted and PRs Welcome 😆 |
||
|
|
||
| if (mapping.initWithStoredValues === false) { | ||
| return connectionID; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably just me being confused ... but I don't get how this works, because in
connectsendDataToConnectionis called with themapping, which AFAICT does not have aconnectionIDproperty 🤔There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gets added in the
connect()method.