You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用react-bootstrap-typeahead实现多异步数据源分组搜索?

可以实现多异步数据源的分组展示需求

完全能用react-bootstrap-typeahead实现你要的多数据源分组展示效果,核心思路是在onSearch中并行处理多个异步请求,给每个数据源的结果打上分组标识,过滤空结果后传给组件,利用组件的分组能力渲染即可。

具体实现步骤:

  1. 并行处理多数据源请求
    在onSearch函数里,用Promise.all同时发起地址数据库查询和本地历史搜索过滤(历史搜索如果是同步数据,用Promise.resolve包装统一流程),确保多个请求并行执行提升效率。

  2. 给结果打分组标识并过滤空数据
    每个数据源返回结果后,给每条数据添加group字段(比如"地址"、"历史搜索"),同时只保留有结果的数据源,避免空分组展示。

  3. 利用组件分组能力渲染
    通过groupBy属性指定分组字段,组件会自动按分组展示结果;如果需要自定义分组样式,用renderMenu和renderGroup做定制。

代码示例:

import { useState } from 'react';
import { Typeahead, TypeaheadMenuItem } from 'react-bootstrap-typeahead';
import 'react-bootstrap-typeahead/css/Typeahead.css';

const SearchBox = () => {
  const [options, setOptions] = useState([]);
  const [isLoading, setIsLoading] = useState(false);

  // 模拟地址数据库查询
  const fetchAddresses = async (query) => {
    const res = await fetch(`/api/addresses?q=${query}`);
    return res.json();
  };

  // 从store获取过滤后的历史搜索
  const getHistorySearches = (query) => {
    const history = window.store.getState().searchHistory;
    return history.filter(item => item.label.toLowerCase().includes(query.toLowerCase()));
  };

  const handleSearch = async (query) => {
    if (!query.trim()) {
      setOptions([]);
      return;
    }

    setIsLoading(true);

    // 并行处理两个数据源,用allSettled避免单个请求失败导致全部失败
    const results = await Promise.allSettled([
      fetchAddresses(query),
      Promise.resolve(getHistorySearches(query))
    ]);

    const groupedOptions = [];

    // 处理地址查询结果
    const addressResult = results[0];
    if (addressResult.status === 'fulfilled' && addressResult.value.length > 0) {
      groupedOptions.push(
        ...addressResult.value.map(item => ({
          ...item,
          group: '地址'
        }))
      );
    }

    // 处理历史搜索结果
    const historyResult = results[1];
    if (historyResult.status === 'fulfilled' && historyResult.value.length > 0) {
      groupedOptions.push(
        ...historyResult.value.map(item => ({
          ...item,
          group: '历史搜索'
        }))
      );
    }

    setOptions(groupedOptions);
    setIsLoading(false);
  };

  return (
    <Typeahead
      onSearch={handleSearch}
      options={options}
      isLoading={isLoading}
      groupBy="group"
      labelKey="label"
      placeholder="输入关键词搜索..."
      // 自定义分组头部样式
      renderGroup={(group, items) => (
        <div className="group-header">
          <strong>{group}</strong>
        </div>
      )}
    />
  );
};

export default SearchBox;

关键注意点:

  • 用Promise.allSettled替代Promise.all,可以避免某个数据源请求失败时,整个搜索流程中断。
  • 确保每个数据源的结果都包含label字段(或通过labelKey指定其他字段),组件才能正确渲染选项文本。
  • 如果本地历史搜索是同步数据,用Promise.resolve包装后可以和异步请求统一处理逻辑,代码更简洁。

内容的提问来源于stack exchange,提问作者Nighto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 22:55:48