React.js中实现双重过滤的方案及问题排查:星级与入住人数过滤失效及代码崩溃问题
嘿,我来帮你搞定这个问题!你遇到的双维度过滤失效、代码崩溃以及key警告的问题,我都给你拆解清楚:
首先解决「should have a unique key prop」警告
这个警告是因为你渲染列表时没有给每个列表项添加唯一的key属性,React需要它来高效更新DOM。你需要两处修改:
- 渲染酒店列表时,给每个酒店的外层
<div>加key,用酒店的唯一ID:key={h.hotel.id} - 渲染房间列表时,给每个房间的外层
<div>加key,用房间的唯一ID:key={room.id}
为什么你之前的入住人数过滤代码会崩溃?
你尝试写的filter((room) => extra.occupancy.includes(room.occupancy.maxAdults))逻辑有两处问题:
hotelRooms数组里的每一项是{hotel, rooms}结构(酒店+该酒店的所有房间),你直接在hotelRooms.filter里遍历room是错误的——这里的遍历对象是酒店,不是房间room.occupancy.maxAdults是数字类型,而你的extra.occupancy是字符串数组(比如["1","2"]),类型不匹配导致判断失效,进而引发逻辑错误
实现双维度过滤的正确逻辑
我们需要分两步过滤,先筛选符合星级的酒店,再给每个符合条件的酒店筛选符合入住人数的房间:
- 保留星级在选中列表里的酒店(你原来的星级过滤逻辑没问题)
- 对每个通过星级筛选的酒店,过滤出房间最大入住成人数在选中列表里的房间(注意要把数字转成字符串匹配)
- 可选优化:如果某个酒店过滤后没有符合条件的房间,可以选择不渲染该酒店,避免显示空的房间列表
完整修改后的代码
import { useEffect, useState } from "react"; import './App.css'; export default function App() { const [hotelRooms, setHotelRooms] = useState([]); const [filter, setFilter] = useState({ ratings: ["1", "2", "3", "4", "5"] }); const [extra, setExtra] = useState ({occupancy: ["1", "2", "3", "4", "5"] }); 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 handleRatingFilter = (e) => { if (e.target.checked) { const temp = [...filter.ratings]; temp.push(e.target.value); setFilter({ ...filter, ratings: temp }); } else { setFilter({ ...filter, ratings: [...filter.ratings.filter((v) => v !== e.target.value)] }); } }; const handleOccupancyExtra = (e) => { if (e.target.checked) { const perm = [...extra.occupancy]; perm.push(e.target.value); setExtra({...extra, occupancy: perm}); } else { setExtra ({ ...extra, occupancy: [...extra.occupancy.filter((d) => d !== e.target.value)] }); } } return ( <div className="App"> <div> {["1", "2", "3", "4", "5"].map((star) => ( <div key={"input-" + star}> <input id={"rated" + star} value={star} name="ratings" type="checkbox" checked={filter.ratings.includes(star)} onChange={handleRatingFilter} /> <label htmlFor={"rated" + star}>Rated {star} star</label> </div> ))} </div> <div> {["1", "2", "3", "4", "5"].map((adults) => ( <div key={"adults" + adults}> <input id={"maximum" + adults} value={adults} name="extra" type="checkbox" checked={extra.occupancy.includes(adults)} onChange={handleOccupancyExtra} /> <label htmlFor={"maximum" + adults}>adults {adults}</label> </div> ))} </div> {hotelRooms .filter((h) => filter.ratings.includes(h.hotel.starRating)) .map((h) => { // 过滤当前酒店下符合入住人数条件的房间 const filteredRooms = h.rooms.filter(room => extra.occupancy.includes(room.occupancy.maxAdults.toString()) ); // 如果没有符合条件的房间,不渲染该酒店 if (filteredRooms.length === 0) return null; return ( <div key={h.hotel.id}> <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> <p style={{ fontWeight: "bold" }}>Rooms:</p> { filteredRooms.map((room) => ( <div key={room.id}> <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> </div> ))} </div> ) })} </div> ); }
这样修改后,你就能同时实现星级和入住人数的双重过滤,也解决了key警告的问题。
内容的提问来源于stack exchange,提问作者someone
相关产品推荐
相关产品推荐

