React Async Select loadoptionがオプションのロードに失敗することがあります。これは、いくつかのクエリセットがloadoptionsに反応しても値がロードされない後の非常に奇妙な現象ですが、ログから結果がバックエンドクエリから適切に取得されたことがわかります。私のコードベースは完全に最新であり、react-selectの新しいリリースと使用しています
「react-select」:「^ 2.1.1」
次に、react-async selectコンポーネントのフロントエンドコードを示します。 getOptions関数でデバウンスを使用して、バックエンド検索クエリの数を減らしています。これは私が推測する問題を引き起こさないはずです。この場合に観察する別のポイントを追加したいと思います。ロードオプション検索インジケータ(...)もこの現象には表示されません。
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;
スティーブ、答えてくれてありがとう。まだ運がありません。私はあなたの応答点に従って応答しようとします。
非同期選択は2/3クエリに対して完全に機能し、その後突然機能しなくなります。これらのケースでは、検索インジケータ(...)も表示されないことがわかります。
お時間をありがとうございました。
返信ありがとうございます。 getOptionValueとgetOptionLabelについて間違っていました。 loadOptionsが応答を取得した場合、これらの関数の両方が呼び出されます。そのため、以前のコードスニペットからヘルパーoptionsValue関数を削除し、(この投稿でも)に従ってコードスニペットを更新します。しかし、まだ運はありません。場合によっては、非同期選択が機能しませんでした。そのような場合のスクリーンショットを撮ろうとします。 local-dbの名前「tamim johnson」で名前を使用していますが、彼を検索すると、応答がありませんでしたが、バックエンドから適切な応答が返されました。これがこのケースのスクリーンショットです
このスクリーンショットがどれほど明確かはわかりません。 Tamim johnsonも私のランクリストの6位にいます。
お時間をいただきありがとうございます。私は何を間違っているのか、何かを見逃しているのか見当がつきません。
これは、「tamim johnson」という名前のユーザー検索のプレビュータブ応答です。
人々はこの問題を探すつもりであることがわかりました。そこで、問題を修正するコードの更新部分を投稿しています。 async-awaitから通常のコールバック関数に変換すると、問題が修正されます。スティーブと他の人に感謝します。
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;
コードの下にいくつかのメモがあります。次のようなものを探しています:
_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()
が文字列を返す同期メソッドである場合、コンポーネント全体をオーバーライドする必要はありません(スタイル変更の場合でも)actionOnSelectedOption
をnoop
メソッドにデフォルト設定すると、それを呼び出すための条件は不要になります。inputValue
を追跡します。外部(ラッパー)に何らかの必要性がない限り、その状態を管理しようとする必要はありません。defaultOptions
は次のいずれかです。loadOptions
を呼び出しません)true
(loadOptions
メソッドから自動ロードします)callback
型ではなくpromise応答を使用して、promiseを返します。getOptions()
メソッドをdebounce
でラップすることにより、コンポーネントでthis
スコープを壊しているのではないかと思っています。 debounce
を使用したことがないので、確かに言うことはできません。そのラッパーをプルして、コードをテストしてみてください。
問題は、Lodashのデバウンス機能がこれに適していないことです。 Lodashは
デバウンスされた関数への後続の呼び出しは、最後のfunc呼び出しの結果を返します
しないこと:
後続の呼び出しは、次のfunc呼び出しの結果に解決されるpromiseを返します
これは、デバウンスされたloadOptions prop関数への待機期間内にある各呼び出しが実際に最後のfunc呼び出しを返すことを意味します。
代わりに、プロミスを返すデバウンス機能を使用します
例えば:
import debounce from "debounce-promise";
//...
this.getOptions = debounce(this.getOptions.bind(this), 500);
完全な説明を参照してください https://github.com/JedWatson/react-select/issues/3075#issuecomment-450194917