React中基于useState对象数组实现多关键词搜索过滤方案咨询
我来帮你搞定这个搜索功能!你的数据结构有点特殊——数组里每个元素是单个键的分类对象,所以过滤时要注意保留所有分类(哪怕对应结果为空),这也是你之前没成功的关键之一。下面是完整的解决方案:
import Card from '../components/Card' import React, { useState, useEffect } from 'react'; export default function IndexPage({ data, search }) { const [filteredBySearch, setFilteredBySearch] = useState(data); useEffect(() => { // 搜索框为空时,直接恢复原始数据 if (!search.trim()) { setFilteredBySearch(data); return; } // 处理搜索关键词:转小写、按任意空格拆分、过滤空字符串(兼容多空格输入) const searchKeywords = search.toLowerCase().split(/\s+/).filter(word => word); // 遍历每个分类,生成过滤后的新数据结构 const filteredData = data.map(categoryObj => { // 获取当前分类的名称和对应的物品列表 const categoryName = Object.keys(categoryObj)[0]; const items = categoryObj[categoryName]; // 过滤当前分类下的物品:只要匹配任意一个关键词就保留 const filteredItems = items.filter(item => { // 把物品的所有可搜索字段(name/desc/allergens)转小写拼接,统一匹配 const itemSearchText = `${item.name.toLowerCase()} ${item.desc.toLowerCase()} ${(item.allergens || '').toLowerCase()}`; // 检查是否有至少一个关键词出现在物品文本中 return searchKeywords.some(keyword => itemSearchText.includes(keyword)); }); // 返回新的分类对象:保留原分类名,值为过滤后的物品数组(空数组也保留) return { [categoryName]: filteredItems }; }); setFilteredBySearch(filteredData); }, [search, data]); // 当搜索词或原始数据变化时,重新执行过滤 return ( <div className="main-content"> <div className="card-container"> {filteredBySearch.map((el, i) => { const categoryName = Object.keys(el)[0]; return ( <div key={i}> <h2 className="category" id={categoryName}>{categoryName}</h2> {el[categoryName].map((itm, index) => ( <Card key={index} infoItem={itm} /> ))} </div> ); })} </div> <style jsx>{`...`}</style> </div> ); }
关键逻辑说明:
关键词处理:
- 把搜索词转成小写,实现不区分大小写的搜索;
- 用
split(/\s+/)按任意数量空格拆分,避免多空格导致的空关键词问题。
分类保留规则:
- 遍历原始数据的每个分类,不管过滤后物品是否为空,都会保留该分类对象(空数组也会保留),完全符合你给出的示例要求。
物品匹配规则:
- 把物品的
name、desc、allergens(兼容空值)字段拼接成统一的小写文本; - 用
some判断物品是否匹配任意一个搜索关键词,满足你示例2中多关键词分别匹配不同物品的需求。
- 把物品的
状态更新时机:
- 通过
useEffect监听search和原始data的变化,每次搜索词或数据源改变时自动重新过滤,保证状态和视图同步。
- 通过
内容的提问来源于stack exchange,提问作者Avaenity
相关产品推荐
相关产品推荐

