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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 06:27:57