如何在React中实现支持多选的动态筛选功能?
问题修复:多选复选框筛选功能失效
核心问题分析
filterList未重置:每次触发筛选时,filterList会不断累加选中值,导致筛选条件混乱。- 依赖DOM获取状态:React中应通过state跟踪表单控件状态,而非直接操作DOM,否则会出现状态不同步的问题。
- 筛选数据源错误:用已筛选的
hotelsList作为数据源,会导致后续筛选基于上一次结果,而非原始数据。 - 筛选逻辑错误:循环内直接
return会提前退出,无法正确判断是否满足任一筛选条件。 - Free Wi-Fi复选框未绑定事件:该复选框没有绑定
handleFilterCheckbox,点击不会触发筛选。
修复步骤与完整代码
import { useState } from 'react' import './cards.styles.css' import Card from '../card/Card' import hotels from '../../data/hotels_array' export default function Cards(){ // 原始数据、当前展示列表、选中的筛选项状态 const [hotelsList, setHotelsList] = useState(hotels) const [selectedFilters, setSelectedFilters] = useState([]) const handleSortChange = (e) => { const sortValue = e.target.value // 排序始终基于原始数据或当前筛选后的数据,保持逻辑一致 const targetList = selectedFilters.length > 0 ? hotelsList : hotels const copyHotelsList = [...targetList] if(sortValue === "sort-default"){ // 默认排序回到原始筛选状态 setHotelsList(selectedFilters.length > 0 ? filterHotels(selectedFilters) : hotels) }else{ copyHotelsList.sort((a, b) => { if(sortValue === "sort-price-lh"){ return a.fromPrice - b.fromPrice }else if (sortValue === "sort-price-hl"){ return b.fromPrice - a.fromPrice }else if(sortValue === "sort-review-score"){ return b.guestRating - a.guestRating } return 0 }) setHotelsList(copyHotelsList) } } // 封装筛选逻辑,基于原始数据 const filterHotels = (filters) => { if(filters.length === 0) return hotels return hotels.filter(hotel => { // 检查酒店是否满足任一筛选条件:位置匹配 或 包含免费WiFi const matchesLocation = filters.includes(hotel.locationName) const matchesWifi = filters.includes("wififree") && hotel.hasFreeWifi // 假设数据中有hasFreeWifi字段,需根据实际调整 return matchesLocation || matchesWifi }) } const handleFilterCheckbox = (e) => { const value = e.target.value let updatedFilters = [...selectedFilters] // 更新选中的筛选项:选中则添加,取消则移除 if(e.target.checked){ updatedFilters.push(value) }else{ updatedFilters = updatedFilters.filter(item => item !== value) } setSelectedFilters(updatedFilters) // 基于原始数据重新筛选 const filtered = filterHotels(updatedFilters) setHotelsList(filtered) } const hotelCards = hotelsList.map(hotel =>{ return ( <Card key={hotel.hotelId} {...hotel} /> ) }) const hotelsListUniqueByLocation = [...new Map(hotels.map(item => [item.locationName, item])).values()]; const hotelLocations = hotelsListUniqueByLocation.map(location =>{ if(location.locationName !== ""){ return ( <li key={location.locationName}> <input type="checkbox" id={location.locationName} value={location.locationName} onChange={handleFilterCheckbox} className="filter_checkbox" checked={selectedFilters.includes(location.locationName)} // 同步选中状态 /> <label htmlFor={location.locationName} className='fs12p'>{location.locationName}</label> </li> ) } }) return( <div className="results_container"> <aside> <h3>Filter</h3> Sorted by: <select onChange={handleSortChange}> <option value="sort-default">Recommended</option> <option value="sort-price-lh">Price (low to high)</option> <option value="sort-price-hl">Price (high to low)</option> <option value="sort-review-score">Review score</option> </select> <div> <input type="checkbox" value="wififree" id="wififree" className="filter_checkbox" onChange={handleFilterCheckbox} checked={selectedFilters.includes("wififree")} // 同步选中状态 /> <label htmlFor="wififree" className='fs12p'>Free Wi-Fi</label> </div> <div> <ul className='hotel_locations'> {hotelLocations} </ul> </div> </aside> <section className='cards_container container'> {hotelCards} </section> </div> ) }
关键优化点说明
- 用state跟踪筛选状态:
selectedFilters存储所有选中的筛选值,确保React可以正确同步UI和状态。 - 基于原始数据筛选:始终从
hotels数组筛选,避免多次筛选导致数据丢失。 - 简化筛选逻辑:用
includes和逻辑或(||)判断是否满足任一条件,替代冗余循环。 - 同步复选框选中状态:给每个复选框添加
checked属性,确保UI与state一致。 - 封装筛选函数:将筛选逻辑抽离为单独函数,提高代码复用性和可维护性。
内容的提问来源于stack exchange,提问作者threelyons0405
相关产品推荐
相关产品推荐

