React多条件过滤器状态的正确改写方法及输入过滤失效问题解决
解决React多条件过滤中输入框删除字符失效的问题
你的问题核心在于过滤逻辑依赖了已经被修改后的activities状态,而非原始数据源allActivities。当你输入字符时,activities会被逐步缩小范围;但删除字符时,你只能在已经过滤后的小数据集里重新筛选,无法恢复到原始的完整数据,所以看起来没有变化。
下面是修复后的代码和思路:
第一步:重构状态与过滤逻辑
我们需要把所有过滤条件(类型勾选状态、搜索关键词、参与者数量)都作为独立状态保存,然后统一基于原始的allActivities进行过滤,而不是每次修改activities本身。
import { useState, useCallback } from 'react'; const [activities, setActivities] = useState(allActivities); const [checked, setChecked] = useState<string[]>([]); const [searchKeyword, setSearchKeyword] = useState(''); // 新增搜索关键词状态 const [minParticipants, setMinParticipants] = useState(1); // 重命名变量更清晰 // 统一过滤函数:基于原始数据,整合所有条件 const applyFilters = useCallback(() => { let filtered = [...allActivities]; // 1. 类型过滤:未勾选的类型不显示(按你的需求逻辑,若勾选则隐藏该类型,可根据实际调整) filtered = filtered.filter(({ type }) => !checked.includes(type)); // 2. 关键词过滤 if (searchKeyword) { filtered = filtered.filter(item => item.activity.toLowerCase().includes(searchKeyword.toLowerCase()) // 建议忽略大小写提升体验 ); } // 3. 参与者数量过滤 filtered = filtered.filter(item => item.participants >= minParticipants); setActivities(filtered); }, [allActivities, checked, searchKeyword, minParticipants]); // 组件初始化时执行一次过滤 useEffect(() => { applyFilters(); }, [applyFilters]);
第二步:修改事件处理函数
现在各个交互只需要更新对应的条件状态,然后让统一的过滤函数生效即可:
// 类型勾选切换 const switchType = (event: React.ChangeEvent<HTMLInputElement>) => { const currentType = event.target.value; const newChecked = checked.includes(currentType) ? checked.filter(type => type !== currentType) : [...checked, currentType]; setChecked(newChecked); }; // 输入框搜索 const inputSearch = (event: React.ChangeEvent<HTMLInputElement>) => { setSearchKeyword(event.target.value); }; // 参与者数量过滤 const countSearch = (event: React.ChangeEvent<HTMLInputElement>) => { setMinParticipants(Number(event.target.value) || 1); // 处理空输入的默认值 };
第三步:调整渲染为受控组件
确保输入框的显示与状态一致,避免UI和状态不一致的问题:
<Input value={searchKeyword} onChange={inputSearch} startAdornment={ <InputAdornment position="start"> <SearchIcon /> </InputAdornment> } /> <Input type="number" value={minParticipants} onChange={countSearch} startAdornment={ <InputAdornment position="start" className={classes.participantsTextField} > <PersonIcon /> </InputAdornment> } />
额外优化提示
类型过滤逻辑校验:你原来的逻辑是
!checked.includes(type),也就是勾选的类型会被隐藏。如果你的需求是「勾选的类型才显示」,需要改成:filtered = filtered.filter(({ type }) => checked.length === 0 || checked.includes(type));这样当没有勾选任何类型时,会显示所有活动。
性能优化:使用
useCallback包裹applyFilters,避免每次渲染都创建新函数;如果allActivities是外部传入的props,建议用useMemo缓存,减少不必要的过滤触发。
内容的提问来源于stack exchange,提问作者Festina
相关产品推荐
相关产品推荐

