React中useState实现鞋品数组品牌复选框筛选与渲染问题
解决React中品牌复选框筛选鞋品数组的逻辑问题
问题核心
当前实现的filterBrandHandler函数错误地将筛选后的数组追加到现有数组中,导致fetchedData变成二维数组,无法实现「勾选时添加对应品牌商品、取消勾选时移除对应品牌商品」的正确筛选逻辑。
问题分析
- 数据结构错误:
setFetchData((current) => [...current, filterByBrand])会把筛选得到的数组作为单个元素推入原数组,最终fetchedData变成[原始数据, [筛选数据1], [筛选数据2]]的嵌套结构 - 逻辑方向错误:直接修改
fetchedData会丢失原始数据的引用,取消勾选时无法基于原始数据重新计算筛选结果,只能在已被修改的数组上继续过滤,导致逻辑混乱
解决方案
正确的思路是维护选中品牌的集合,基于原始数据实时计算筛选结果,而不是直接修改存储数据的状态:
- 新增状态存储选中的品牌集合
- 复选框切换时,仅更新选中品牌集合
- 根据选中品牌集合,从原始
result数组中计算出最终要渲染的筛选数据
修改后的完整代码
import type { NextPage } from 'next' import { useState, useReducer } from "react"; import Pagination from '../../../components/Pagination'; import Modal from '../../../components/Modal'; type MenSneakersPageProps = { result: any[] } // 定义鞋品类型(替换any,提升类型安全性) type Sneaker = { id: number; shortDescription: string; brand?: { id: number; name: string; }; // 可根据实际结构补充其他字段 } const MenSneakers: NextPage<MenSneakersPageProps> = ({ result }) => { // 维护选中品牌的集合,避免重复 const [selectedBrands, setSelectedBrands] = useState<Set<string>>(new Set()) const [modal, dispatch] = useReducer(reducer, initialState) // 优化品牌列表生成:用Set去重,更简洁高效 const brandList = Array.from( new Set(result.map(item => item.brand?.name).filter(Boolean) as string[]) ).sort() // 处理复选框切换:仅更新选中品牌集合 const filterBrandHandler = (event: React.ChangeEvent<HTMLInputElement>) => { const { value, checked } = event.target; setSelectedBrands(prev => { const newSet = new Set(prev); if (checked) { newSet.add(value); } else { newSet.delete(value); } return newSet; }); } // 实时计算筛选后的结果 const filteredData = selectedBrands.size === 0 ? result // 没有选中任何品牌时,返回全部数据 : result.filter(item => selectedBrands.has(item.brand?.name || '')) return ( <div className='px-2'> <Modal onOpen={modal.secondModal} setPopUp={() => dispatch({ type:'closeModal2', value: false})}> <h2 className='text-2xl border-bottom border-b-4 border-black w-20 font-semibold pb-2'>Brands</h2> <hr/> {brandList.map((item, index) => ( <ul className='mt-6' key={index}> <li className='my-6'> <input className="mr-2" type='checkbox' id={`brand-${index}`} // 修复id重复问题 value={item} name='brand' checked={selectedBrands.has(item)} // 设置正确的选中状态 onChange={filterBrandHandler} /> {item} </li> </ul> ))} </Modal> <Pagination data={filteredData} title="" pageLimit={2} dataLimit={30}/> </div> ) } export default MenSneakers
关键优化点
- 状态分离:用
selectedBrands集合单独维护选中的品牌,避免直接修改数据数组 - 基于原始数据计算:每次筛选都从原始
result数组出发,确保取消勾选时能正确还原数据 - 类型优化:新增
Sneaker类型替换any,提升代码可维护性 - 品牌列表生成优化:用
Set去重,比循环判断更高效简洁 - 修复复选框问题:设置正确的
checked状态,避免复选框状态与实际选中集合不一致
内容的提问来源于stack exchange,提问作者schmulzcode
相关产品推荐
相关产品推荐

