如何在React中结合Select组件实现perNight与标题筛选功能?
解决方案:React + Firebase 实现酒店标题/价格筛选功能
核心问题梳理
你当前的代码已经完成了基础数据获取和搜索,但未将filter状态与搜索逻辑结合,同时perNight字段实际上已经通过hotel对象传递到了Card组件中(无需从Information组件获取),只需直接使用即可。以下是分步优化方案:
步骤1:修正状态与组件匹配
首先将filter的初始值与select默认选项对齐,避免状态不一致:
// 原代码 const [filter, setFilter] = useState('All'); // 修改为 const [filter, setFilter] = useState("Filter By");
步骤2:整合筛选与搜索逻辑
将筛选逻辑抽离为单独变量,结合search和filter状态实现精准筛选:
// 在return前添加筛选函数 const filteredHotels = hotels.filter((item: NewHotelType) => { // 搜索词为空时返回全部酒店 if (!search.trim()) return true; switch (filter) { case "title": // 不区分大小写的标题包含匹配(比完全相等更实用) return item.title.toLowerCase().includes(search.toLowerCase()); case "perNight": // 处理价格筛选:将搜索词转为数字,非有效数字则返回全部 const targetPrice = Number(search); return isNaN(targetPrice) ? true : item.perNight === targetPrice; default: // 默认按标题筛选 return item.title.toLowerCase().includes(search.toLowerCase()); } });
步骤3:优化用户体验
- 给select选项添加中文标签,更直观
- 根据筛选类型动态修改搜索框提示文字
- 修复Firestore订阅的内存泄漏问题(添加清理函数)
修改后的完整代码
import { DocumentData, onSnapshot, QuerySnapshot } from "firebase/firestore"; import { useEffect, useState } from "react"; import { hotelsCollection } from "../lib/controller"; import { NewHotelType } from "../types/hotel"; import Information from "./Information"; function Card() { const [hotels, setHotels] = useState<NewHotelType[]>([]); const [search, setSearch] = useState(""); const [filter, setFilter] = useState("Filter By"); useEffect(() => { // 订阅Firestore数据,添加清理函数防止内存泄漏 const unsubscribe = onSnapshot(hotelsCollection, (snapshot: QuerySnapshot<DocumentData>) => { setHotels( snapshot.docs.map(doc => ({ id: doc.id, ...doc.data(), })) ); }); return unsubscribe; }, []); const filteredHotels = hotels.filter((item: NewHotelType) => { if (!search.trim()) return true; switch (filter) { case "title": return item.title.toLowerCase().includes(search.toLowerCase()); case "perNight": const targetPrice = Number(search); return isNaN(targetPrice) ? true : item.perNight === targetPrice; default: return item.title.toLowerCase().includes(search.toLowerCase()); } }); return ( <div className="card"> <select onChange={(e) => setFilter(e.target.value)} value={filter}> <option value="Filter By">筛选类型</option> <option value="perNight">每晚价格</option> <option value="title">酒店标题</option> </select> <div className="search"> <input className="inputsearch" value={search} type="text" placeholder={filter === "perNight" ? "输入价格筛选" : "搜索酒店"} onChange={(e) => setSearch(e.target.value)} /> </div> {filteredHotels.length ? ( <div> {filteredHotels.map((hotel: NewHotelType) => ( <Information key={hotel.id} hotel={hotel} /> ))} </div> ) : ( <h2 className="no-hotels">暂无酒店</h2> )} </div> ); } export default Card;
扩展:实现价格区间筛选(可选)
如果需要支持“最低-最高价格”区间筛选,可以添加额外状态和输入框:
// 添加价格区间状态 const [minPrice, setMinPrice] = useState(""); const [maxPrice, setMaxPrice] = useState(""); // 在select下方添加区间输入框(仅当选中价格筛选时显示) {filter === "perNight" && ( <div className="price-range"> <input type="number" placeholder="最低价格" value={minPrice} onChange={(e) => setMinPrice(e.target.value)} /> <span>-</span> <input type="number" placeholder="最高价格" value={maxPrice} onChange={(e) => setMaxPrice(e.target.value)} /> </div> )} // 修改价格筛选逻辑 case "perNight": const min = minPrice ? Number(minPrice) : 0; const max = maxPrice ? Number(maxPrice) : Infinity; return item.perNight >= min && item.perNight <= max;
内容的提问来源于stack exchange,提问作者Emilia
相关产品推荐
相关产品推荐

