-
Notifications
You must be signed in to change notification settings - Fork 1.2k
[Resource Picker] Fix reference to old callback function #1451
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
[Resource Picker] Fix reference to old callback function #1451
Conversation
👋 Thanks for opening your first pull request. A contributor should give feedback soon. If you haven’t already, please check out the contributing guidelines. You can also join #polaris on the Shopify Partners Slack. |
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.
Thanks for working on this fix! Instead of keeping the reference to this.props
in the subscribed callback, let’s unsubscribe and resubscribe the updated callbacks in componentDidUpdate
.
componentDidUpdate() {
const {onSelection, onCancel} = this.props;
this. appBridgeResourcePicker.unsubscribe();
if (onSelection != null) {
this. appBridgeResourcePicker.subscribe(AppBridgeResourcePicker.Action.SELECT, onSelection);
}
if (onCancel != null) {
this. appBridgeResourcePicker.subscribe(AppBridgeResourcePicker.Action.CANCEL, onCancel);
}
}
Also, add a test or two to get the coverage > 90%. Happy to help with this if needed!
@tmlayton - Updated PR to address feedback. Sorry about not getting back to this quickly, I caught a nasty cold last week! |
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.
Just a couple minor changes to the tests to expect that we call unsubscribe
, otherwise this looks great, nice work and thanks for the contribution!
@tmlayton Updated |
Looks great, thanks for the contribution! |
These settings may change dynamically at runtime, but since the value when the component mounted is captured it may reference stale data.
🎉 Thanks for your contribution to Polaris React! |
WHY are these changes introduced?
When developing an app that adds line items to a draft order, I noticed that my ResourcePicker kept resetting my line items to the initial state. Since this component requires being inside of an embedded app and I am working on a private project, I put together an example app that demonstrates the issue: https://github.com/katzenbar/shopify-resource-picker-bug
This example app takes the products selected in the ResourcePicker, and adds them to the end of the list in the card. https://github.com/katzenbar/shopify-resource-picker-bug/blob/master/app/javascript/components/ProductPage.tsx#L24-L28
But when
handleSelection
is run, theproducts
array is empty. This results in the old selection being replaced.The expected behavior should be that the newly selected products are added to the end of the list.
I believe part of reproducing this issue is using React Hooks instead of
setState
, but I have not tested to verify that is the case.WHAT is this pull request doing?
When pulling out
onSelection
andonCancel
incomponentDidMount
through destructuring, you will keep a reference to the version of that function when the component was mounted. If data these functions reference is updated, these function references become stale and are not updated. In theory, if you were to initially have these callbacks be null and then change them to a real function they would never get called.To fix this, I changed the code to always register a subscriber for
onSelection
andonCancel
and get the current reference of these fromthis.props
when the callback fires. This seems more efficient that trying to track subscribe/unsubscribe inside ofcomponentDidUpdate
in the general case. I've tested this on my sample application in Chrome, and it works as I expect now.If anyone else is experiencing this issue, a workaround is to treat the
ResourcePicker
like theToast
example in the documentation and only render it when you are about to open the modal.