如何从 react-select 中的一长串选项中有效地 select
How to select efficiently from a long list of options in react-select
我的用例是允许用户从大约 8000 家公司的长列表中 select 一个代码。我在组件安装时获取所有公司,所以我真的不需要 react-select 的异步功能。问题实际上是显示和滚动 8000 个项目(如 this one 等几个未解决的问题中所述)。
我的想法是,当用户无法对这么大的列表做任何有意义的事情时,为什么要显示 8000 个条目。相反,为什么不显示最多 5 个匹配项。随着用户键入的内容越来越多,匹配也会越来越好。具体来说:
- 当输入为空时,不显示任何选项
- 当输入单个字符时,仍然会有数百个匹配项,但只显示前5个
- 随着用户不断打字,匹配项的数量会减少,但仍限制在 5 个以内。但是它们会更相关。
我没有在任何地方看到这个解决方案,所以想知道它是否有意义。还想找出用 react-select 实现它的最佳方法是什么。我尝试了以下两种方法 - 你能想到更好的方法吗:
方法一:使用 Async React Select
虽然我不需要异步获取,但我可以使用此功能来筛选选项。它似乎工作得很好:
const filterCompanies = (value: string) => {
const inputValue = value.trim().toLowerCase();
const inputLength = inputValue.length;
let count = 0;
return inputLength === 0
? []
: companies.filter(company => {
const keep =
count < 5 &&
(company.ticker.toLowerCase().indexOf(inputValue) >= 0 ||
company.name.toLowerCase().indexOf(inputValue) >= 0);
if (keep) {
count += 1;
}
return keep;
});
};
const promiseOptions = (inputValue: string) =>
Promise.resolve(filterCompanies(inputValue));
return (
<AsyncSelect<Company>
loadOptions={promiseOptions}
value={selectedCompany}
getOptionLabel={option => `${option.ticker} - ${option.name}`}
getOptionValue={option => option.ticker}
isClearable={true}
isSearchable={true}
onChange={handleChange}
/>
);
方法二:使用filterOption
这里我使用filterOption
直接过滤列表。然而,它并不能很好地工作——filterOption 函数非常短视——它一次只能获得一个候选选项,并且需要决定它是否匹配。使用这种方法,我无法确定我是否超过了显示 5 个选项的限制。最终结果:在空白输入的情况下,我显示了所有 8000 个选项,当用户开始输入时,选项的数量减少了,但仍然很大——所以迟缓仍然存在。我原以为 filterOption
对于我的用例来说是更直接的方法,但事实证明它不如异步方法好。我错过了什么吗?
const filterOption = (candidate: Option, input: string) => {
const { ticker, name } = candidate.data;
const inputVal = input.toLowerCase();
return (
ticker.toLowerCase().indexOf(inputVal) >= 0 ||
name.toLowerCase().indexOf(inputVal) >= 0
);
};
return (
<ReactSelect
options={companies}
value={selectedCompany}
filterOption={filterOption}
getOptionLabel={option => `${option.ticker} - ${option.name}`}
getOptionValue={option => option.ticker}
isClearable={true}
isSearchable={true}
onChange={handleChange}
/>
);
你可以试试用react-window替换menulist组件
参考:https://github.com/JedWatson/react-select/issues/3128#issuecomment-431397942
我的用例是允许用户从大约 8000 家公司的长列表中 select 一个代码。我在组件安装时获取所有公司,所以我真的不需要 react-select 的异步功能。问题实际上是显示和滚动 8000 个项目(如 this one 等几个未解决的问题中所述)。
我的想法是,当用户无法对这么大的列表做任何有意义的事情时,为什么要显示 8000 个条目。相反,为什么不显示最多 5 个匹配项。随着用户键入的内容越来越多,匹配也会越来越好。具体来说:
- 当输入为空时,不显示任何选项
- 当输入单个字符时,仍然会有数百个匹配项,但只显示前5个
- 随着用户不断打字,匹配项的数量会减少,但仍限制在 5 个以内。但是它们会更相关。
我没有在任何地方看到这个解决方案,所以想知道它是否有意义。还想找出用 react-select 实现它的最佳方法是什么。我尝试了以下两种方法 - 你能想到更好的方法吗:
方法一:使用 Async React Select
虽然我不需要异步获取,但我可以使用此功能来筛选选项。它似乎工作得很好:
const filterCompanies = (value: string) => {
const inputValue = value.trim().toLowerCase();
const inputLength = inputValue.length;
let count = 0;
return inputLength === 0
? []
: companies.filter(company => {
const keep =
count < 5 &&
(company.ticker.toLowerCase().indexOf(inputValue) >= 0 ||
company.name.toLowerCase().indexOf(inputValue) >= 0);
if (keep) {
count += 1;
}
return keep;
});
};
const promiseOptions = (inputValue: string) =>
Promise.resolve(filterCompanies(inputValue));
return (
<AsyncSelect<Company>
loadOptions={promiseOptions}
value={selectedCompany}
getOptionLabel={option => `${option.ticker} - ${option.name}`}
getOptionValue={option => option.ticker}
isClearable={true}
isSearchable={true}
onChange={handleChange}
/>
);
方法二:使用filterOption
这里我使用filterOption
直接过滤列表。然而,它并不能很好地工作——filterOption 函数非常短视——它一次只能获得一个候选选项,并且需要决定它是否匹配。使用这种方法,我无法确定我是否超过了显示 5 个选项的限制。最终结果:在空白输入的情况下,我显示了所有 8000 个选项,当用户开始输入时,选项的数量减少了,但仍然很大——所以迟缓仍然存在。我原以为 filterOption
对于我的用例来说是更直接的方法,但事实证明它不如异步方法好。我错过了什么吗?
const filterOption = (candidate: Option, input: string) => {
const { ticker, name } = candidate.data;
const inputVal = input.toLowerCase();
return (
ticker.toLowerCase().indexOf(inputVal) >= 0 ||
name.toLowerCase().indexOf(inputVal) >= 0
);
};
return (
<ReactSelect
options={companies}
value={selectedCompany}
filterOption={filterOption}
getOptionLabel={option => `${option.ticker} - ${option.name}`}
getOptionValue={option => option.ticker}
isClearable={true}
isSearchable={true}
onChange={handleChange}
/>
);
你可以试试用react-window替换menulist组件
参考:https://github.com/JedWatson/react-select/issues/3128#issuecomment-431397942