Skip to content
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

Merged
merged 17 commits into from
Jan 31, 2023

Conversation

sai6855
Copy link
Contributor

@sai6855 sai6855 commented Jan 5, 2023

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).

@mui-bot
Copy link

mui-bot commented Jan 5, 2023

Messages
📖 Netlify deploy preview: https://deploy-preview-35735--material-ui.netlify.app/

@material-ui/lab: parsed: +0.14% , gzip: +0.14%
@material-ui/unstyled: parsed: +0.27% , gzip: +0.30%

Details of bundle changes

Generated by 🚫 dangerJS against e6f5294

@zannager zannager added the component: autocomplete This is the name of the generic UI component, not the React module! label Jan 5, 2023
@zannager zannager requested a review from michaldudak January 5, 2023 13:04
@sai6855 sai6855 changed the title [Autocomplete] prevent reset to scroll position when new options are added [Autocomplete] prevent reset scroll position when new options are added Jan 5, 2023
@sai6855 sai6855 marked this pull request as draft January 5, 2023 13:14
@sai6855 sai6855 marked this pull request as ready for review January 5, 2023 13:29
@sai6855 sai6855 marked this pull request as draft January 5, 2023 18:06
@sai6855 sai6855 marked this pull request as ready for review January 6, 2023 18:13
@ZeeshanTamboli ZeeshanTamboli added the bug 🐛 Something doesn't work label Jan 11, 2023
@ZeeshanTamboli ZeeshanTamboli changed the title [Autocomplete] prevent reset scroll position when new options are added [Autocomplete] Prevent reset scroll position when new options are added Jan 11, 2023
Copy link
Member

@ZeeshanTamboli ZeeshanTamboli left a 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.

@sai6855
Copy link
Contributor Author

sai6855 commented Jan 14, 2023

@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

@sai6855 sai6855 requested review from ZeeshanTamboli and removed request for michaldudak January 18, 2023 12:20
Copy link
Member

@ZeeshanTamboli ZeeshanTamboli left a 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).

@vitalivasileuski-st
Copy link

We at SensorTower tested this PR for AutoComplete with custom Option and Listbox components. ListBox inside uses InfiniteScroll component and some additional not related components. With useMemo for the ListBox it works perfectly fine.

@sai6855
Copy link
Contributor Author

sai6855 commented Jan 27, 2023

Comment made in issue by one of the user that this PR is working fine in their set-up : #29508 (comment)

@ZeeshanTamboli
Copy link
Member

@michaldudak Can you take a look?

@sai6855 sai6855 requested a review from michaldudak January 29, 2023 10:12
Copy link
Member

@michaldudak michaldudak left a 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!

@sai6855
Copy link
Contributor Author

sai6855 commented Jan 30, 2023

Thanks!! Once this is merged I'll resume working on #35653

@hbjORbj hbjORbj merged commit 14dba8d into mui:master Jan 31, 2023
Copy link
Member

@oliviertassinari oliviertassinari left a 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);
Copy link
Member

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.

Suggested change
return getOptionLabel(option) === getOptionLabel(previousHighlightedOption);
return option === previousHighlightedOption;

Copy link
Member

@ZeeshanTamboli ZeeshanTamboli Feb 6, 2023

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.

Copy link
Member

@oliviertassinari oliviertassinari Feb 6, 2023

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?

Copy link
Member

@ZeeshanTamboli ZeeshanTamboli Feb 8, 2023

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?

Copy link
Member

@oliviertassinari oliviertassinari Feb 8, 2023

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.

Copy link
Member

@michaldudak michaldudak Feb 9, 2023

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.

@sai6855 sai6855 deleted the autocomplete-scrolltop branch February 1, 2023 05:10
previousProps.filteredOptions &&
previousProps.filteredOptions.length !== filteredOptions.length &&
(multiple
? previousProps.value.every((val, i) => getOptionLabel(value[i]) === getOptionLabel(val))
Copy link

@waful waful Feb 9, 2023

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:

  1. Autocomplete is using the multiple, disableCloseOnSelect, and filterSelectedOptions flags
  2. There is currently one selected option
  3. 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

@honia19
Copy link

honia19 commented Sep 13, 2023

I'm really sorry, is it already released? If yes, what kind of version?

@michaldudak
Copy link
Member

This was released in @mui/material 5.11.7

@honia19
Copy link

honia19 commented Sep 14, 2023

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.

@sai6855
Copy link
Contributor Author

sai6855 commented Sep 14, 2023

@honia19 can you create a new issue with reproduction

@honia19
Copy link

honia19 commented Sep 14, 2023

@honia19 can you create a new issue with reproduction

Okay I will tag you

@honia19
Copy link

honia19 commented Jan 18, 2024

@quoc-jordan-an
Copy link

@sai6855 Link to reproduce: https://codesandbox.io/s/autocomplete-scroll-bug-39wfv

Your problem can be solved by adding role: "list-box" to ListboxProps.

Kudos to this comment: #30249 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: autocomplete This is the name of the generic UI component, not the React module!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Autocomplete] List gets scrolled to the top when new data is received