By added focusFirstSuggestion: true break the selection. It only selects the first suggestion. Is there anything else apart from setting this to true that needs to be done?
This is the object I am paasing to autosuggest.
const autosuggestProps = {
suggestions: [].concat(children || [], suggestions),
getSuggestionValue: identity,
shouldRenderSuggestions: () => true,
renderSuggestion: this.renderSuggestion.bind(this),
onSuggestionsUpdateRequested: this.onSuggestionsUpdateRequested,
onSuggestionSelected: this.onSuggestionSelected,
focusFirstSuggestion: true,
theme: this.props.theme,
inputProps: {
onChange: this.onChange,
onBlur: this.onBlur,
onKeyPress: this.onKeyPress,
value: displayInput,
placeholder: this.props.placeholder,
}
};
<Autosuggest {...autosuggestProps}/>
@avjpl I'm not sure I understand the issue you are experiencing.
Here is a Codepen that demonstrates focusFirstSuggestion={true}.
Could you please elaborate a bit more, and update the Codepen accordingly to demonstrate the problem?
I apologise for not being clear, but I wasn't sure why the behaviour I was seeing was happening.
After seeing your Codepen, thank for that, I went back to my codebase and narrowed down what was causing the problem.
It was caused by the following line.
suggestions: [].concat(suggestions)
But I am not quite sure why.
Here is a Codepen example.
I get the same behaviour with slice too
suggestions: suggestions.slice()
Thanks @avjpl, now I see that Up/Down doesn't work properly.
@rickhanlonii Could you have a look?
@moroshko @avjpl I'll take a look
@rickhanlonii Any luck?
@moroshko not yet, last week was pretty busy. I'll take a look this week.
I've just hit this problem, too.
If you take a look at react-autosuggest/src/Autosuggest.js:
componentWillReceiveProps(nextProps) {
if (nextProps.suggestions !== this.props.suggestions) {
const {
suggestions, inputProps, shouldRenderSuggestions,
isCollapsed, revealSuggestions, lastAction
} = nextProps;
const { value } = inputProps;
if (suggestions.length > 0 && shouldRenderSuggestions(value)) {
this.maybeFocusFirstSuggestion();
if (isCollapsed && lastAction !== 'click' && lastAction !== 'enter') {
revealSuggestions();
}
}
}
}
This code is doing an identity comparison on the list of suggestions. So if you compute the suggestions prop dynamically in the parent component's render() method, this code path will run on every render and always set the focus to the first element, even if the list of suggestions has not actually changed.
This code should probably do a deep array comparison instead.
On second thought, a deep comparison is probably wrong. What the code should actually do is check whether either nothing is selected or whatever is selected is no longer in the list of suggestions, and only in this case select the first element.
That's still in O(n) though, so it's not really faster than doing a deep array comparison.
Also note that if your state management code mutates suggestions (which is a silly thing to do, of course), by doing e.g.
// suggestions is ['Hamburg', 'Havana']
suggestions.length = 0
suggestions.unshift('Bangkok', 'Berlin')
the implementation above will fail to detect the change.
Probably makes sense to shallowly compare suggestions in componentWillReceiveProps instead of ===. I'll fix this.
This is fixed in 5.0.1 now.
Can confirm, 5.0.1 fixes the issue for me. Thank you for fixing this so quickly!
Great diagnosis @fixpunkt!
Most helpful comment
This is fixed in 5.0.1 now.