如何从 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 个匹配项。随着用户键入的内容越来越多,匹配也会越来越好。具体来说:

我没有在任何地方看到这个解决方案,所以想知道它是否有意义。还想找出用 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