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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 21:45:03