-
Notifications
You must be signed in to change notification settings - Fork 75
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
Allow infinite dependent keys when using withOnyx #385
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 |
---|---|---|
|
@@ -11,6 +11,7 @@ dist/ | |
|
||
# IDEs | ||
.idea | ||
.vscode | ||
|
||
# Decrypted private key we do not want to commit | ||
.github/OSBotify-private-key.asc |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,15 @@ function getDisplayName(component) { | |
return component.displayName || component.name || 'Component'; | ||
} | ||
|
||
/** | ||
* Removes all the keys from state that are unrelated to the onyx data being mapped to the component. | ||
* | ||
* @param {Object} state of the component | ||
* @param {Object} onyxToStateMapping the object holding all of the mapping configuration for the component | ||
* @returns {Object} | ||
*/ | ||
const getOnyxDataFromState = (state, onyxToStateMapping) => _.pick(state, _.keys(onyxToStateMapping)); | ||
|
||
export default function (mapOnyxToState, shouldDelayUpdates = false) { | ||
// A list of keys that must be present in tempState before we can render the WrappedComponent | ||
const requiredKeysForInit = _.chain(mapOnyxToState) | ||
|
@@ -92,16 +101,20 @@ export default function (mapOnyxToState, shouldDelayUpdates = false) { | |
this.checkEvictableKeys(); | ||
} | ||
|
||
componentDidUpdate(prevProps) { | ||
componentDidUpdate() { | ||
// When the state is passed to the key functions with Str.result(), omit anything | ||
// from state that was not part of the mapped keys. | ||
const onyxDataFromState = getOnyxDataFromState(this.state, mapOnyxToState); | ||
|
||
// If any of the mappings use data from the props, then when the props change, all the | ||
// connections need to be reconnected with the new props | ||
_.each(mapOnyxToState, (mapping, propertyName) => { | ||
const previousKey = Str.result(mapping.key, prevProps); | ||
const newKey = Str.result(mapping.key, this.props); | ||
_.each(mapOnyxToState, (mapping, propName) => { | ||
const previousKey = mapping.previousKey; | ||
const newKey = Str.result(mapping.key, {...this.props, ...onyxDataFromState}); | ||
if (previousKey !== newKey) { | ||
Onyx.disconnect(this.activeConnectionIDs[previousKey], previousKey); | ||
delete this.activeConnectionIDs[previousKey]; | ||
this.connectMappingToOnyx(mapping, propertyName); | ||
this.connectMappingToOnyx(mapping, propName); | ||
} | ||
}); | ||
this.checkEvictableKeys(); | ||
|
@@ -110,9 +123,8 @@ export default function (mapOnyxToState, shouldDelayUpdates = false) { | |
componentWillUnmount() { | ||
// Disconnect everything from Onyx | ||
_.each(mapOnyxToState, (mapping) => { | ||
const key = Str.result(mapping.key, this.props); | ||
const connectionID = this.activeConnectionIDs[key]; | ||
Onyx.disconnect(connectionID, key); | ||
const key = Str.result(mapping.key, {...this.props, ...getOnyxDataFromState(this.state, mapOnyxToState)}); | ||
Onyx.disconnect(this.activeConnectionIDs[key], key); | ||
}); | ||
} | ||
|
||
|
@@ -244,7 +256,14 @@ export default function (mapOnyxToState, shouldDelayUpdates = false) { | |
* component | ||
*/ | ||
connectMappingToOnyx(mapping, statePropertyName) { | ||
const key = Str.result(mapping.key, this.props); | ||
const key = Str.result(mapping.key, {...this.props, ...getOnyxDataFromState(this.state, mapOnyxToState)}); | ||
|
||
// Remember the previous key so that if it ever changes, the component will reconnect to Onyx | ||
// in componentDidUpdate | ||
if (statePropertyName !== 'initialValue' && mapOnyxToState[statePropertyName]) { | ||
// eslint-disable-next-line no-param-reassign | ||
mapOnyxToState[statePropertyName].previousKey = key; | ||
} | ||
Comment on lines
+263
to
+266
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. This is another small change from the previous PR. When |
||
|
||
// eslint-disable-next-line rulesdir/prefer-onyx-connect-in-libs | ||
this.activeConnectionIDs[key] = Onyx.connect({ | ||
|
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 one change that is different than the original PR. I realized that the
unmount()
was still trying to use the old method for getting the key name. This would probably lead to somewhat of a memory leak because it could cause Onyx to keep a bunch of connections that are never disconnected from when components unmount.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.
Does removing this change introduce the same problem as previously?
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.
I can give it a try. That's a good hunch
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.
No, it doesn't appear to. I think the changes for batched updates was probably the biggest help for preventing the performance problem we saw last time.
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.
Hm... That's making me nervous.
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.
Are you referring to the change in
onUnmount()
specifically, or this PR in general?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 PR in general.
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.
To dig into this further, I tried the following things:
withOnyx
changes to the code and tried it out. Result: I was not able to duplicate the original performance problem.initialValue
change). After fixing only that fatal error I was still not able to reproduce the original performance problem, though I did see that the report switching was taking about 2-3x longer.I'm not sure if this fatal error was what we experienced when the original PR was deployed. We definitely witnessed the app hanging and no one could report any JS console errors or record performance profiles, but that was about it.
Conclusion: I am feeling pretty good about the changes in this PR in general. The worst that can happen is we have to do another quick revert, which would stink, but it's also not the end of the world.
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.
One thing I did not try was using the original commit from Onyx and a commit from App on the same day... I can do that if you would like.
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.
Sounds good to me. I'll continue my testing.