Réaction asynchrone L'option de chargement échoue parfois pour charger l'option. Il s’agit d’un phénomène très étrange après que plusieurs requêtes aient réagi. Loadoptions ne charge aucune valeur, mais je peux voir dans le journal que les résultats proviennent correctement d’une requête. Ma base de code est totalement à jour avec réag-select nouvelle version et en utilisant
"réagir-sélectionner": "^ 2.1.1"
Voici mon code frontal pour le composant react-async select. J'utilise debounce dans ma fonction getOptions pour réduire le nombre de requêtes de recherche d'arrière-plan. Cela ne devrait poser aucun problème, je suppose. Je voudrais ajouter un autre point que j'observe dans ce cas, l'indicateur loadoptions serach (...) n'apparaît pas non plus dans ce phénomène.
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;
Merci pour votre réponse Steve. Toujours pas de chance. J'essaie de répondre en fonction de vos points de réponse.
async select fonctionne parfaitement pour 2/3 requêtes et cesse ensuite de fonctionner. Un comportement pouvant être distingué, j’observe que, dans ces cas, les indicateurs de recherche (...) ne sont pas non plus indiqués.
Merci beaucoup pour votre temps.
Merci beaucoup pour votre réponse à nouveau. Je me suis trompé à propos de getOptionValue et de getOptionLabel. Si loadOptions obtient une réponse, ces deux fonctions sont appelées. J'ai donc retiré la fonction optionsValue de mon assistant de mon extrait de code précédent et mis à jour mon extrait de code en fonction de (dans cet article également). Mais toujours pas de chance. Dans certains cas, async-select ne fonctionnait pas. J'essaie de prendre une capture d'écran d'un tel cas. Je ne nomme pas utiliser dans mon nom local-db "tamim johnson" mais quand je le fouille je ne reçois aucune réponse, mais je reçois une réponse correcte en retour. Voici la capture d'écran de cette affaire
Je ne sais pas à quel point cette capture d'écran est claire. Tamim Johnson également en 6ème position dans mon classement.
Merci monsieur pour votre temps. Je n'ai aucune idée de ce que je fais mal ou manque quelque chose.
Ceci est la réponse de l'onglet d'aperçu pour la recherche de l'utilisateur nommé "tamim johnson".
J'ai découvert que les gens ont l'intention de rechercher ce problème. Donc, je publie ma partie mise à jour du code qui résout le problème. La conversion de asynchrone-wait en une fonction de rappel normale corrige mon problème. Un merci spécial à Steve et aux autres.
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;
Certaines notes peuvent être trouvées sous le code. Vous cherchez quelque chose comme ça:
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import AsyncSelect from 'react-select/lib/Async';
import debounce from 'lodash.debounce';
import noop from 'lodash.noop';
import i18n from 'myinternationalization';
const propTypes = {
searchApiUrl: PropTypes.string.isRequired,
limit: PropTypes.number,
defaultValue: PropTypes.object,
actionOnSelectedOption: PropTypes.func
};
const defaultProps = {
limit: 25,
defaultValue: null,
actionOnSelectedOption: noop
};
export default class SearchableSelect extends Component {
static propTypes = propTypes;
static defaultProps = defaultProps;
constructor(props) {
super(props);
this.state = {
inputValue: '',
searchApiUrl: props.searchApiUrl,
limit: props.limit,
selectedOption: this.props.defaultValue,
actionOnSelectedOption: props.actionOnSelectedOption
};
this.getOptions = debounce(this.getOptions.bind(this), 500);
this.handleChange = this.handleChange.bind(this);
this.noOptionsMessage = this.noOptionsMessage.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
}
getOptionValue = (option) => option.id;
getOptionLabel = (option) => option.name;
handleChange(selectedOption) {
this.setState({
selectedOption: selectedOption
});
// this is for update action on selectedOption
this.state.actionOnSelectedOption(selectedOption.value);
}
async getOptions(inputValue) {
if (!inputValue) {
return [];
}
const response = await fetch(
`${this.state.searchApiUrl}?search=${inputValue}&limit=${
this.state.limit
}`
);
const json = await response.json();
return json.results;
}
handleInputChange(inputValue) {
this.setState({ inputValue });
return inputValue;
}
noOptionsMessage(inputValue) {
if (this.props.options.length) return null;
if (!inputValue) {
return i18n.get('app.commons.label.search');
}
return i18n.get('app.commons.errors.emptySearchResult');
}
render() {
const { defaultOptions, placeholder } = this.props;
const { selectedOption } = this.state;
return (
<AsyncSelect
cacheOptions
value={selectedOption}
noOptionsMessage={this.noOptionsMessage}
getOptionValue={this.getOptionValue}
getOptionLabel={this.getOptionLabel}
defaultOptions={defaultOptions}
loadOptions={this.getOptions}
placeholder={placeholder}
onChange={this.handleChange}
/>
);
}
}
i18n.get()
est une méthode synchrone renvoyant une chaîne, vous n'avez pas à remplacer tout le composant (même pour les modifications de style). actionOnSelectedOption
sur une méthode noop
, vous n'avez plus besoin de Pour pouvoir l'appeler.inputValue
en interne. À moins que vous n'ayez des besoins externes (votre wrapper), il n'est pas nécessaire d'essayer de gérer son état.defaultOptions
est soit loadOptions
tant que vous n'avez pas filtré)true
(chargera automatiquement à partir de votre méthode loadOptions
)callback
.Je me demande si, en encapsulant votre méthode getOptions()
dans debounce
, vous rompez la portée this
avec votre composant. Je ne peux pas dire avec certitude, car je n’avais jamais utilisé debounce
auparavant. Vous pouvez tirer ce wrapper et essayer votre code à tester.
Le problème est que la fonction anti-rebond de Lodash ne convient pas à cela. Lodash précise que
les appels suivants à la fonction debounce renvoient le résultat du dernière invocation de fonction
Pas ça:
les appels suivants renvoient des promesses qui aboutiront au résultat de la prochaine invocation de fonction
Cela signifie que chaque appel entrant dans la période d'attente de la fonction debO debounce de loadOptions renvoie en réalité la dernière invocation de fonction, de sorte que la "vraie" promesse dont nous nous soucions n'est jamais souscrite.
Utilisez plutôt une fonction anti-rebond à retour de promesse
Par exemple:
import debounce from "debounce-promise";
//...
this.getOptions = debounce(this.getOptions.bind(this), 500);
Voir l'explication complète https://github.com/JedWatson/react-select/issues/3075#issuecomment-450194917