-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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
[Autocomplete] Prevent reset scroll position when new options are added #35735
Conversation
@material-ui/lab: parsed: +0.14% , gzip: +0.14% |
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.
I tried to review the code. Someone else familiar with the logic will take a deep look.
I would also recommend investigating why it stopped working in version 5. I would also suggest providing a preview package to the community in the related issue for them to test it out in real-world applications, as this looks complicated with heavy calculations.
@ZeeshanTamboli updated PR description which includes performance demos, and looks like there isn't much difference in render times b/w master and this branch. Let me know if there are any issues with implementation on how performance is calculated |
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.
It looks good to me. Thanks for your work, @sai6855. This needs a review from @michaldudak, though. It would also help if we get a response on #29508 (comment).
We at SensorTower tested this PR for |
Comment made in issue by one of the user that this PR is working fine in their set-up : #29508 (comment) |
@michaldudak Can you take a look? |
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.
Great! I couldn't find any scenario where it fails. Thank you for the fix!
Thanks!! Once this is merged I'll resume working on #35653 |
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.
Nice to see this bug fixed, the solution looks nice 👍
|
||
if (previousHighlightedOption) { | ||
const previousHighlightedOptionExists = filteredOptions.some((option) => { | ||
return getOptionLabel(option) === getOptionLabel(previousHighlightedOption); |
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 we sure about this comparison? I would expect the scroll to reset if no options are equal to be enough.
return getOptionLabel(option) === getOptionLabel(previousHighlightedOption); | |
return option === previousHighlightedOption; |
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.
But in the case when options are objects, it would always reset, with the strict equality always returning false
because they point to different object instances.
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.
it would always reset
Why? I would expect developers to fetch new options, append them, and keep the same reference to the existing options. At least, the bug reproduction we have seem to be compatible with this idea.
If developers re-fetch all the options which leads to creating new references, then maybe they would also expect a scroll reset?
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.
So you're saying that, consider in the test, this is incorrect because developers re-fetch all the options (including a new one), so we should expect to reset? But shouldn't React developers treat objects/arrays as immutable when storing in state (options
prop)? Then it would be a new reference?
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.
Yes, in this test, these look like entirely new options. I think that a scroll reset can make sense.
#26492 makes the case that developers expect support for duplicated option labels.
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.
Actually, we could use isOptionEqualToValue
to determine if two options are the same instead of relying on labels. This should also fix #36114. I created a PR with this approach: #36116
@oliviertassinari resetting the highlight when a reference to an option changes but its value/label does not could lead to a worse DX, for example when a new set of options is received from a server, and it includes the currently highlighted one. I would expect the highlight to remain where it was.
previousProps.filteredOptions && | ||
previousProps.filteredOptions.length !== filteredOptions.length && | ||
(multiple | ||
? previousProps.value.every((val, i) => getOptionLabel(value[i]) === getOptionLabel(val)) |
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 introduces a runtime error TypeError: Cannot read properties of undefined (reading 'label')
at getOptionLabel(value[i])
when under these conditions:
- Autocomplete is using the
multiple
,disableCloseOnSelect
, andfilterSelectedOptions
flags - There is currently one selected option
- You delete the existing option while the dropdown is open
When you delete the option, value
is now []
and so value[i]
is undefined. When fed to getOptionLabel
, it crashes because it expects option to not be undefined.
Line 100: getOptionLabel: getOptionLabelProp = (option) => option.label ?? option
EDIT: issue filed with more details and replication sandbox: #36114
I'm really sorry, is it already released? If yes, what kind of version? |
This was released in @mui/material 5.11.7 |
But it's still not working with infinity scroll when I use the handle onScroll, I'm trying to make components with virtualization and infinity scroll together. And I still see issues with scroll to top when I review new data. |
@honia19 can you create a new issue with reproduction |
Okay I will tag you |
@sai6855 Link to reproduce: https://codesandbox.io/s/autocomplete-scroll-bug-39wfv |
Your problem can be solved by adding Kudos to this comment: #30249 (comment) |
closes: #29508
used logic as per: #33645 (comment)
working video: https://www.loom.com/share/6a38df21a3e2422c973c4b1e3ea9ba7f
working codesandbox demo: https://codesandbox.io/s/nervous-euclid-2ekej7
tests autocomplete performance demo in this PR: https://codesandbox.io/s/blazing-platform-io3mgu?file=/demo.tsx
tests autocomplete performance demo in master https://codesandbox.io/s/nameless-platform-nohxeo?file=/demo.tsx
open consoles for both demos and keep on navigating options and observe actualDuration for both demos, looks like both actualDuration times are in similar range (10-20ms).