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

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))逻辑有两处问题:

  1. hotelRooms数组里的每一项是{hotel, rooms}结构(酒店+该酒店的所有房间),你直接在hotelRooms.filter里遍历room是错误的——这里的遍历对象是酒店,不是房间
  2. room.occupancy.maxAdults是数字类型,而你的extra.occupancy是字符串数组(比如["1","2"]),类型不匹配导致判断失效,进而引发逻辑错误

实现双维度过滤的正确逻辑

我们需要分两步过滤,先筛选符合星级的酒店,再给每个符合条件的酒店筛选符合入住人数的房间:

  1. 保留星级在选中列表里的酒店(你原来的星级过滤逻辑没问题)
  2. 对每个通过星级筛选的酒店,过滤出房间最大入住成人数在选中列表里的房间(注意要把数字转成字符串匹配)
  3. 可选优化:如果某个酒店过滤后没有符合条件的房间,可以选择不渲染该酒店,避免显示空的房间列表

完整修改后的代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 19:58:10