
本文详解如何在 react 中为含嵌套结构的数据(如分组+选项列表)构建健壮的搜索功能,支持实时模糊匹配子项(如 label),动态过滤并保留对应父级分组信息,同时解决清空输入后无法恢复原始数据的问题。
在 react 应用中处理嵌套数据(如分组容器 + 子选项数组)的搜索需求时,常见误区是直接修改原始数据源或忽略搜索状态的可逆性。以 groups 数组为例——每个 group 包含 name 和 options(子对象数组),目标是:当用户输入 “Team 1B” 时,仅返回 Male 9 B 分组,并且其 options 只保留匹配的 { label: “Team 1B”, selected: false };更重要的是,清空搜索框时,必须完整还原所有分组与原始选项。
关键在于分离「原始数据」与「搜索结果」:使用 useState 管理原始数据快照,并在每次输入变更时基于该快照重新计算结果,而非持续覆盖原始状态。
以下是完整、可运行的解决方案:
import React, { useState, useMemo } from 'react'; const App = () => { // ✅ 原始数据 —— 永不直接修改 const initialGroups = [ { 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 } ] } ]; const [searchTerm, setSearchTerm] = useState(''); // ✅ 使用 useMemo 实现高效、纯净的搜索计算 const filteredGroups = useMemo(() => { if (!searchTerm.trim()) return initialGroups; // 清空时还原全部 const lowerTerm = searchTerm.toLowerCase(); return initialGroups .filter(group => group.options.some(option => option.label.toLowerCase().includes(lowerTerm) ) ) .map(group => ({ ...group, options: group.options.filter(option => option.label.toLowerCase().includes(lowerTerm) ) })); }, [searchTerm, initialGroups]); return ( setSearchTerm(e.target.value)} /> {FilteredGroups.length === 0 ? ( No matching teams found.
) : ( filteredGroups.map((group, idx) => (
{group.name}
{group.options.map((opt, i) => ( - {opt.label} {opt.selected ? '(selected)' : ''}
))}
)) )}