如何在React中通过复选框对API返回的酒店数据按星级筛选展示
实现方案
核心逻辑调整说明
- 不要手动调用
document.createElement操作DOM,React基于状态驱动视图,只要更新对应状态就会自动渲染对应内容,手动操作的DOM会被React虚拟DOM渲染覆盖,所以不会生效 - 不要在复选框的
onChange事件中重复调用接口拉取数据,全量数据拉取一次后存在本地做筛选即可,减少不必要的接口请求 - 新增两个状态分别存储全量原始数据和选中的筛选项,避免筛选后丢失原始数据
完整修改后代码
import { useState, useEffect } from 'react' import Header from './Header' // 请根据自己的项目路径调整Header组件的引入 export default function App() { // 存储全量原始酒店数据,避免筛选后丢失源数据 const [allHotelRooms, setAllHotelRooms] = useState([]); // 存储用户选中的星级筛选项 const [selectedStarRatings, setSelectedStarRatings] = useState([]); // 存储筛选后的酒店列表 const [filteredHotels, setFilteredHotels] = useState([]); 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 }) } // 全量数据和初始筛选结果都赋值为拉取到的全部数据 setAllHotelRooms(hotelRooms) setFilteredHotels(hotelRooms) } useEffect(() => { fetchHotels() }, []) // 星级复选框切换处理函数 const handleStarChange = (star) => { let newSelected = [] if (selectedStarRatings.includes(star)) { // 已选中对应星级则移除筛选项 newSelected = selectedStarRatings.filter(item => item !== star) } else { // 未选中对应星级则添加筛选项 newSelected = [...selectedStarRatings, star] } setSelectedStarRatings(newSelected) // 执行筛选逻辑 if (newSelected.length === 0) { // 无选中星级时展示全部酒店 setFilteredHotels(allHotelRooms) } else { // 筛选出星级匹配的酒店 const result = allHotelRooms.filter(h => newSelected.includes(h.hotel.starRating)) setFilteredHotels(result) } } return ( <div className="App"> <Header/> {/* 星级筛选区域 */} <div style={{padding: '10px', borderBottom: '1px solid #eee'}}> <h3>按星级筛选:</h3> {[1,2,3,4,5].map(star => ( <label key={star} style={{marginRight: '15px'}}> <input type="checkbox" checked={selectedStarRatings.includes(star)} onChange={() => handleStarChange(star)} /> {star}星 </label> ))} </div> {/* 渲染筛选后的酒店列表 */} { filteredHotels.map(h => ( <div key={h.hotel.id} style={{padding: '15px', borderBottom: '1px solid #eee'}}> <h2> 名称: {h.hotel.name}</h2> <p> 描述: {h.hotel.description}</p> <p> 星级: {h.hotel.starRating}</p> <p> 邮编: {h.hotel.postcode}</p> <p> 城市: {h.hotel.town}</p> <img src={h.hotel.images?.[0]?.url || ''} alt={h.hotel.name} /> <p style={{ fontWeight: 'bold' }}>房型:</p> { h.rooms.map(room => ( <div key={room.id} style={{paddingLeft: '20px', marginTop: '10px'}}> <h5>入住人数限制</h5> <div> 成人最多: {room.occupancy.maxAdults}</div> <div> 儿童最多: {room.occupancy.maxChildren}</div> <div> 总人数最多: {room.occupancy.maxOverall}</div> <div> 房型: {room.name}</div> <img src={room.images?.[0]?.url || ''} alt={room.name} /> </div> )) } </div> )) } </div> ) }
额外优化提示
- 原代码中直接写
img src={h.hotel.images}是错误的,接口返回的images是数组,需要取数组内的url字段才能正常展示图片 - 列表遍历渲染必须添加
key属性,避免React渲染报错
内容的提问来源于stack exchange,提问作者someone
相关产品推荐
相关产品推荐

