React中如何借助useEffect实现已渲染内容的筛选功能?
筛选功能实现方案
核心修改逻辑
- 新增2组状态分别存储星级筛选条件、成人入住筛选条件,原始接口返回的全量酒店数据全程不做修改,避免筛选后数据丢失
- 将筛选复选框从酒店列表的循环中抽离到全局顶部位置,避免每个酒店重复生成筛选控件
- 渲染列表前先根据筛选条件过滤全量数据,再对过滤后的数据做映射渲染
- 给复选框绑定change事件,实时更新筛选状态触发视图刷新
修改后完整代码
import { useEffect, useState, useRef } from 'react' import Header from './components/Header'; import SearchBar from './components/SearchBar'; export default function App() { const [hotelRooms, setHotelRooms] = useState([]); // 新增:存储选中的星级,支持多选 const [selectedStarRatings, setSelectedStarRatings] = useState([]); // 新增:存储是否开启成人入住筛选 const [filterAdultOption, setFilterAdultOption] = useState(false); const fetchHotels = async () => { const res = await fetch('https://obmng.dbm.guestline.net/api/hotels?collection-id=OBMNG') const hotels = await res.json() const hotelRooms = [] for(const hotel of hotels) { const res = await fetch(`https://obmng.dbm.guestline.net/api/roomRates/OBMNG/${hotel.id}`) const info = await res.json() hotelRooms.push({ hotel, rooms: info.rooms }) } setHotelRooms(hotelRooms) } useEffect(() => { fetchHotels() }, []) // 新增:根据当前筛选条件过滤酒店数据 const filteredHotelList = hotelRooms.filter(hotelItem => { // 星级匹配规则:未选任何星级时全放,选中时匹配对应星级 const isStarMatch = selectedStarRatings.length === 0 ? true : selectedStarRatings.includes(hotelItem.hotel.starRating); // 成人选项匹配规则:未开启筛选时全放,开启时仅保留支持2名及以上成人入住的房型 const isAdultMatch = filterAdultOption ? hotelItem.rooms.some(room => room.occupancy.maxAdults >= 2) : true; return isStarMatch && isAdultMatch; }) return ( <div className="App"> <Header/> {/* 筛选控件移到全局位置 */} <div style={{padding: '16px', borderBottom: '1px solid #eee'}}> <p>星级筛选:</p> <label style={{marginRight: '12px'}}> <input value="1" type="checkbox" onChange={(e) => { const starVal = Number(e.target.value); if(e.target.checked) { setSelectedStarRatings(prev => [...prev, starVal]) } else { setSelectedStarRatings(prev => prev.filter(item => item !== starVal)) } }} /> 1星级 </label> <label style={{marginRight: '12px'}}> <input value="2" type="checkbox" onChange={(e) => { const starVal = Number(e.target.value); if(e.target.checked) { setSelectedStarRatings(prev => [...prev, starVal]) } else { setSelectedStarRatings(prev => prev.filter(item => item !== starVal)) } }} /> 2星级 </label> <label style={{marginRight: '12px'}}> <input value="3" type="checkbox" onChange={(e) => { const starVal = Number(e.target.value); if(e.target.checked) { setSelectedStarRatings(prev => [...prev, starVal]) } else { setSelectedStarRatings(prev => prev.filter(item => item !== starVal)) } }} /> 3星级 </label> <label style={{marginRight: '12px'}}> <input value="4" type="checkbox" onChange={(e) => { const starVal = Number(e.target.value); if(e.target.checked) { setSelectedStarRatings(prev => [...prev, starVal]) } else { setSelectedStarRatings(prev => prev.filter(item => item !== starVal)) } }} /> 4星级 </label> <label style={{marginRight: '12px'}}> <input value="5" type="checkbox" onChange={(e) => { const starVal = Number(e.target.value); if(e.target.checked) { setSelectedStarRatings(prev => [...prev, starVal]) } else { setSelectedStarRatings(prev => prev.filter(item => item !== starVal)) } }} /> 5星级 </label> <br /> <label style={{marginTop: '8px', display: 'inline-block'}}> <input type="checkbox" onChange={(e) => setFilterAdultOption(e.target.checked)} /> 仅显示支持2名及以上成人入住的房型 </label> </div> {/* 改用过滤后的数据做映射渲染 */} { filteredHotelList.map(h => ( <div key={h.hotel.id} style={{padding: '16px', borderBottom: '1px solid #eee'}}> <h2> Name: {h.hotel.name}</h2> <p> Description: {h.hotel.description}</p> <p> Rating: {h.hotel.starRating}</p> <p> Postcode: {h.hotel.postcode}</p> <p> City: {h.hotel.town}</p> <img src={h.hotel.images} alt={h.hotel.name} style={{maxWidth: '200px'}}/> <p style={{ fontWeight: 'bold' }}>Rooms:</p> { h.rooms.map(room => ( <div key={room.id} style={{marginLeft: '16px', marginBottom: '12px'}}> <h5>Occupancy</h5> <div> Adults: {room.occupancy.maxAdults}</div> <div> Children: {room.occupancy.maxChildren}</div> <div> Maximum guests: {room.occupancy.maxOverall}</div> <div> Room type: {room.name}</div> <img src={room.images} alt={room.name} style={{maxWidth: '150px'}}/> </div> )) } </div> )) } </div> ); }
补充说明
如果需要新增其他筛选维度,只要新增对应的筛选状态,在filteredHotelList的过滤规则里补充匹配逻辑即可。所有筛选操作不修改原始数据,切换筛选条件时无需重新请求接口。
内容的提问来源于stack exchange,提问作者someone
相关产品推荐
相关产品推荐

