React Async Select loadoption sometimes fail to loads the option. This is a very strange phenomenon after couple of set of queries react loadoptions don't load any value but i can see from log that results properly came from backend query. My codebase is totally up to date with react-select new release and using
"react-select": "^2.1.1"
Here is my front end code for react-async select component. I do use debounce in my getOptions function to reduce number of backend search query. This should not cause any problem i guess. I would like to add another point that i observe in this case, loadoptions serach indicator ( ... ) also not appear in this phenomenon.
import React from 'react';
import AsyncSelect from 'react-select/lib/Async';
import Typography from '@material-ui/core/Typography';
import i18n from 'react-intl-universal';
const _ = require('lodash');
class SearchableSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: '',
searchApiUrl: props.searchApiUrl,
limit: props.limit,
selectedOption: this.props.defaultValue
};
this.getOptions = _.debounce(this.getOptions.bind(this), 500);
//this.getOptions = this.getOptions.bind(this);
this.handleChange = this.handleChange.bind(this);
this.noOptionsMessage = this.noOptionsMessage.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleChange(selectedOption) {
this.setState({
selectedOption: selectedOption
});
if (this.props.actionOnSelectedOption) {
// this is for update action on selectedOption
this.props.actionOnSelectedOption(selectedOption.value);
}
}
handleInputChange(inputValue) {
this.setState({ inputValue });
return inputValue;
}
async getOptions(inputValue, callback) {
console.log('in getOptions'); // never print
if (!inputValue) {
return callback([]);
}
const response = await fetch(
`${this.state.searchApiUrl}?search=${inputValue}&limit=${
this.state.limit
}`
);
const json = await response.json();
console.log('results', json.results); // never print
return callback(json.results);
}
noOptionsMessage(props) {
if (this.state.inputValue === '') {
return (
<Typography {...props.innerProps} align="center" variant="title">
{i18n.get('app.commons.label.search')}
</Typography>
);
}
return (
<Typography {...props.innerProps} align="center" variant="title">
{i18n.get('app.commons.errors.emptySearchResult')}
</Typography>
);
}
getOptionValue = option => {
return option.value || option.id;
};
getOptionLabel = option => {
return option.label || option.name;
};
render() {
const { defaultOptions, placeholder } = this.props;
return (
<AsyncSelect
cacheOptions
value={this.state.selectedOption}
noOptionsMessage={this.noOptionsMessage}
getOptionValue={this.getOptionValue}
getOptionLabel={this.getOptionLabel}
defaultOptions={defaultOptions}
loadOptions={this.getOptions}
placeholder={placeholder}
onChange={this.handleChange}
/>
);
}
}
export default SearchableSelect;
Thank you for your answer Steve. Still no luck. I try to response according to your response points.
async select work perfectly for 2/3 queries and after that it suddenly stop working. One distinguishable behaviour i observe that for those cases search indicators ( ... ) also not showing.
Thank you so much for you time.
Thank you so much for your response again. I was wrong about getOptionValue and getOptionLabel. If loadOptions got response both these function called. So i removed my helper optionsValue function from my previous code snippet and update my code-snippet according to ( In this post also ). But still no luck. In some cases async-select didn't work. I try to take a screenshot one such case. I do name use in my local-db name "tamim johnson" but when i search him i didn't get any response but got proper response back from back-end. Here is the screenshot of this case
I not sure how clear this screenshot is. Tamim johnson also in 6th position in my ranklist.
Thank you sir for your time. I have no clue what i am doing wrong or missing something.
This is preview tab response for user search named "tamim johnson".
I found out that people intend to look for this problem. So i am posting my update portion of code that fix the issue. Converting from async-await to normal callback function fix my issue. Special thanks to Steve and others.
import React from 'react';
import AsyncSelect from 'react-select/lib/Async';
import { loadingMessage, noOptionsMessage } from './utils';
import _ from 'lodash';
class SearchableSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedOption: this.props.defaultValue
};
this.getOptions = _.debounce(this.getOptions.bind(this), 500);
}
handleChange = selectedOption => {
this.setState({
selectedOption: selectedOption
});
if (this.props.actionOnSelectedOption) {
this.props.actionOnSelectedOption(selectedOption.value);
}
};
mapOptionsToValues = options => {
return options.map(option => ({
value: option.id,
label: option.name
}));
};
getOptions = (inputValue, callback) => {
if (!inputValue) {
return callback([]);
}
const { searchApiUrl } = this.props;
const limit =
this.props.limit || process.env['REACT_APP_DROPDOWN_ITEMS_LIMIT'] || 5;
const queryAdder = searchApiUrl.indexOf('?') === -1 ? '?' : '&';
const fetchURL = `${searchApiUrl}${queryAdder}search=${inputValue}&limit=${limit}`;
fetch(fetchURL).then(response => {
response.json().then(data => {
const results = data.results;
if (this.props.mapOptionsToValues)
callback(this.props.mapOptionsToValues(results));
else callback(this.mapOptionsToValues(results));
});
});
};
render() {
const { defaultOptions, placeholder, inputId } = this.props;
return (
<AsyncSelect
inputId={inputId}
cacheOptions
value={this.state.selectedOption}
defaultOptions={defaultOptions}
loadOptions={this.getOptions}
placeholder={placeholder}
onChange={this.handleChange}
noOptionsMessage={noOptionsMessage}
loadingMessage={loadingMessage}
/>
);
}
}
export default SearchableSelect;