You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 17:16:07