When typing a query into an asynchronous Autocomplete before the request finishes loading, Autocomplete with autoHighlight set to true does not highlight the first option. Only after pressing another key do first options get highlighted as they should. Everything then works as expected until the user clears the textfield and starts over.
The first option should be selected when the request finishes loading.
Steps:
autoHighlight is onI just upgraded from v4.0.0-alpha.50 where this bug did not yet exist. So something must have changed in the recent merges.
| Tech | Version |
| ----------- | ------- |
| Material-UI Lab | v4.0.0-alpha.53 |
| React | 16.13.1 |
| Browser | Chrome |
| TypeScript | 3.9.2 |
Hi @mstykow waiting core members for a response I propose a solution
diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
index db79387ae..862209657 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
@@ -97,6 +97,7 @@ export default function useAutocomplete(props) {
onClose,
onHighlightChange,
onInputChange,
+ loading = false,
onOpen,
open: openProp,
openOnFocus = false,
@@ -402,13 +403,21 @@ export default function useAutocomplete(props) {
}
});
+ React.useEffect(() => {
+ if (!loading && filteredOptions.length > 0) {
+ changeHighlightedIndex('reset', 'next');
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [loading, changeHighlightedIndex]);
+
@marcosvega91 Thank you very much for your quick proposal! I guess this could work. Two questions:
1) why do you nest your if blocks instead of using &&
2) this hook will fire every time loading changes (when changes in query text trigger new fetches) but the bug actually only occurs on the first load, that is, when user first enters the textfield. so we'd fire more often than necessary and this indicates to me that we haven't really found the source of the problem yet.
Hey
Nice. Maybe one more improvement simplifying your if statement:
if (!loading && filteredOptions.length) {
Is there a way that does not require leaking the loading state to the hook?
Interesting question, mmm... we can use options in the useEffect. If options change and the length > 0 we can reset the highlight.
The problem here is that because options are passed from user we need to pay attention to avoid unexpected call to useEffect
It seems that ignoring the filterOptions dependency leads to this bug
https://github.com/mui-org/material-ui/blob/f63646ab4a169081783842b21b70fdb447a47243/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js#L448-L450
@marcosvega91 Yeah, I share the same concern, getOptionSelected and getOptionLabel are, most of the time, not memoized. Regarding the option, adding it as dependency could be less risky.
Maybe?
diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
index db79387ae..3688d704b 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
@@ -448,6 +448,7 @@ export default function useAutocomplete(props) {
// Ignore filterOptions => options, getOptionSelected, getOptionLabel)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
+ filteredOptions.length,
value,
popupOpen,
filterSelectedOptions,
@oliviertassinari Dealing with arrays and objects in the dependences is always a problem. In this case can be worked.
@marcosvega91 Do you have a preference for the resolution? Do you want to take care of it? :)
I leave the resolution to @mstykow that has discovered the bug, otherwise I can do it.
It's ok for your resolution but I think that in both cases a test case is needed 馃槃
Sorry, this is my first issue here. What do you mean by "I leave the resolution to XYZ"?
I personally would prefer you stop ignoring the filteredOptions dependency on the existing useEffect hook if that gets rid of the bug. But didn't the person who decided to ignore the dependency have a good reason for it?
@mstykow I mean that if you have the pleasure you can open a PR and fix the bug 馃挴
Done: https://github.com/mui-org/material-ui/pull/21090. I did not add any tests because I did not see any other tests checking that dependency changes fire the effect hook. In fact, I was surprised to see that for a component as complex as this there were less than 10 tests. All of this leaves me feeling a little uneasy about the changes I just made. Who knows what side-effects it'll have no longer ignoring the filteredOptions! @oliviertassinari
I was looking in the wrong place and now see some tests failing. Checking it out now.