
本文详解如何在 react 中为含嵌套结构(如分组+选项列表)的数据实现精准、可重置的搜索功能,支持按子项字段模糊匹配并动态过滤层级,同时修复常见状态管理与事件传递错误。
在构建表单、配置面板或团队/角色选择器等场景中,常需对具有层级结构的数据(如 groups → options)进行搜索。例如,给定多个分组,每个分组包含若干带 label 的选项,目标是:输入关键词(如 “Team 1B”),仅返回匹配的分组及其内部精确匹配的选项,且清空输入时能完整恢复原始数据。
上述需求看似简单,但实际开发中易出现三大典型问题:
- ❌ 状态未正确初始化与重置:useState 初始值设为过滤后结果,导致清空输入时无法还原全部 groups;
- ❌ 事件对象未正确传递:onChange 回调中未将 Event 传入搜索逻辑,造成 event.target.value 报错;
- ❌ 过滤逻辑不完整:仅匹配 options.label,忽略对 group.name 的搜索(如搜 “Male 9 A” 应返回整个分组),且未做空字符串兜底处理。
以下是完整、健壮的实现方案:
✅ 正确实现(含状态管理 + 清空恢复)
import React, { useState, useMemo } from 'react'; const groups = [ { name: "Male 9 A", options: [ { label: "Team 1", selected: false }, { label: "Team 2", selected: false }, { label: "Team 3", selected: false }, { label: "Team 4", selected: false }, { label: "Team 5", selected: false } ] }, { name: "Male 9 B", options: [ { label: "Team 1B", selected: false }, { label: "Team 2B", selected: false }, { label: "Team 3B", selected: false }, { label: "Team 4B", selected: false }, { label: "Team 5B", selected: false } ] } ]; export default function App() { const [searchTerm, setSearchTerm] = useState(''); // 使用 useMemo 缓存搜索结果,避免重复计算 const filteredGroups = useMemo(() => { if (!searchTerm.trim()) return groups; // 空搜索 → 返回全部 const lowerTerm = searchTerm.toLowerCase(); return groups .filter(group => // 匹配分组名 OR 分组内任意选项的 label group.name.toLowerCase().includes(lowerTerm) || group.options.some(option => option.label.toLowerCase().includes(lowerTerm)) ) .map(group => ({ ...group, options: group.options.filter(option => option.label.toLowerCase().includes(lowerTerm) ) })); }, [searchTerm, groups]); return ( setSearchTerm(e.target.value)} /> {filteredGroups.length === 0 ? ( No matches found.
) : ( filteredGroups.map((group, idx) => (
{group.name}
{group.options.map((option, i) => ( - {option.label}
))}
)) )}