React诊所筛选组件异常:点击搜索无过滤,输入时自动生效
核心问题原因
点击搜索按钮无过滤效果,但输入框直接输入能正常过滤,根源在于搜索按钮的点击事件逻辑错误,具体问题点如下:
1. 按钮点击事件的搜索词来源错误
搜索按钮的点击处理函数handleChange中,错误地尝试获取按钮的e.target.value作为搜索关键词,但该按钮没有设置value属性,导致searchClinic被设置为空字符串。此时useEffect监听searchClinic变化后,因搜索词为空,直接将clinicListFiltered重置为完整诊所列表,所以显示全部数据。
2. 状态更新顺序与重复数据请求
每次点击按钮都会重新调用getClinic获取完整列表,并且先将clinicListFiltered设置为完整列表,再更新searchClinic。即使按钮有有效value,这种顺序也会导致先显示完整列表,再触发过滤,同时重复请求数据完全没必要。
3. 过滤逻辑的大小写匹配问题
原useEffect中的过滤逻辑没有将搜索词转为小写,可能导致大小写不匹配的过滤失效(比如输入"Madrid"无法匹配"madrid")。
修复方案
方案1:修正搜索按钮的逻辑,使用输入框当前值过滤
重命名handleChange为handleSearch(语义更清晰),调整逻辑如下:
const handleSearch = (e) => { e.preventDefault(); // 若未获取过诊所列表,先请求数据;否则直接用已有数据过滤 if (clinicList.length === 0) { setIsLoading(true); getClinic().then((response) => { setClinicList(response); // 用输入框当前的搜索词直接过滤 const lowerCaseSearch = searchClinic.toLowerCase(); const filterList = response.filter((element) => element.province?.toString().toLowerCase().includes(lowerCaseSearch) ); setClinicListFiltered(filterList); setIsLoading(false); }).catch((error) => { console.error(error); setIsLoading(false); }); } else { // 已有数据,直接执行过滤 const lowerCaseSearch = searchClinic.toLowerCase(); const filterList = clinicList.filter((element) => element.province?.toString().toLowerCase().includes(lowerCaseSearch) ); setClinicListFiltered(filterList); } };
同时修改按钮的onClick绑定:
<button className="btn bg-teal-600 hover:bg-teal-700 text-white text-sm active:bg-teal-700 px-8 outline-none focus:outline-none" type="button" onClick={handleSearch} >Buscar</button>
方案2:优化useEffect的过滤逻辑
修正大小写匹配问题,并添加clinicList到依赖项,确保列表更新后也能正确过滤:
useEffect(() => { if (searchClinic.length > 0) { const lowerCaseSearch = searchClinic.toLowerCase(); const filterList = clinicList.filter((element) => element.province?.toString().toLowerCase().includes(lowerCaseSearch) ); setClinicListFiltered(filterList); } else { setClinicListFiltered(clinicList); } }, [searchClinic, clinicList]); // 添加clinicList到依赖数组
额外优化:修复加载状态判断
原代码中用!clinicListFiltered判断加载状态是错误的(空数组的布尔值为true),应该用isLoading状态:
{isLoading ? <Loader /> : clinicListFiltered.map((clinicFilter) => ( <div className="card bg-white px-2 py-3 h-36 md:h-32" key={clinicFilter.id}> {/* 诊所项内容 */} </div> )) }
总结
点击按钮无过滤的本质是按钮事件错误地使用自身无效value作为搜索词,重置了搜索状态;而输入框输入时直接更新searchClinic,此时列表已加载完成,useEffect能正确触发过滤逻辑,所以效果正常。修复后即可实现点击按钮按输入框内容过滤的需求。
内容的提问来源于stack exchange,提问作者cuencadelrio

