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

如何重构React代码使h2标题仅在需要时渲染?

问题解决:修正酒店列表加载时错误显示无酒店提示的问题

核心问题分析

你的代码中isLoading初始值设为false,而Firestore的onSnapshot是异步获取数据的。组件挂载后会立刻渲染,此时hotels是空数组、isLoading为false,导致无酒店提示提前显示,直到数据加载完成才会切换到列表。

修改后的完整代码

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 Hotel() {
  const [hotels, setHotels] = useState<NewHotelType[]>([]);
  const [search, setSearch] = useState("");
  const [sortState, setSortState] = useState("");
  // 初始设为true,标记数据正在加载
  const [isLoading, setIsLoading] = useState(true);

  useEffect(
    () => {
      // 保存unsubscribe函数,组件卸载时取消监听
      const unsubscribe = onSnapshot(
        hotelsCollection,
        (snapshot: QuerySnapshot<DocumentData>) => {
          setHotels(
            snapshot.docs.map(doc => ({
              id: doc.id,
              ...doc.data(),
            }))
          );
          // 数据获取完成,结束加载状态
          setIsLoading(false);
        },
        // 处理数据获取错误,同样结束加载状态
        (error) => {
          console.error("加载酒店数据失败:", error);
          setIsLoading(false);
        }
      );

      return unsubscribe;
    },
    []
  );

  return (
    <div className="card">
      <select
        className="select"
        defaultValue={""}
        onChange={(e) => setSortState(e.target.value)}
      >
        <option value="" disabled>Filter By</option>
        <option value="name">Name</option>
        <option value="price">Price</option>
      </select>
      <div className="search">
        <input
          className="inputsearch"
          value={search}
          type="text"
          placeholder="Search for the hotel"
          onChange={(e) => setSearch(e.target.value)}
        />
      </div>

      {/* 简化渲染逻辑,按加载状态 -> 有数据 -> 无数据的顺序判断 */}
      {isLoading ? (
        <div>Loading..</div>
      ) : hotels.length > 0 ? (
        <div>
          {hotels
            .filter((item: NewHotelType) => {
              // 优化搜索逻辑:支持模糊匹配,不区分大小写
              if (!search) return true;
              return item.title?.toLowerCase().includes(search.toLowerCase());
            })
            .sort((a, b) => {
              if (sortState === "name") {
                return a.title?.localeCompare(b.title) || 0;
              }
              if (sortState === "price") {
                return Number(a.perNight) - Number(b.perNight);
              }
              return 0;
            })
            .map((hotel: NewHotelType) => (
              <Information key={hotel.id} hotel={hotel} />
            ))}
        </div>
      ) : (
        <h2 className="no-hotels">There are no hotels. Please add one</h2>
      )}
    </div>
  );
}

export default Hotel;

关键修改点

  1. 修正加载状态初始值:将isLoading初始设为true,确保组件挂载后先显示加载提示,而非无酒店文本。
  2. 完善Firestore监听逻辑:
    • 在onSnapshot的成功回调中设置setIsLoading(false),数据加载完成后结束加载状态。
    • 添加错误回调,即使加载失败也会结束加载状态,避免页面一直显示加载提示。
    • 返回unsubscribe函数,组件卸载时取消Firestore监听,防止内存泄漏。
  3. 简化渲染判断逻辑:按加载中 -> 有数据 -> 无数据的顺序判断,代码更清晰,避免嵌套逻辑混乱。
  4. 优化搜索过滤逻辑:将严格匹配改为模糊匹配(不区分大小写),提升用户搜索体验(可选修改,根据需求调整)。
  5. 修正select选项错误:原代码中第一个option的value="disabled"不符合规范,改为value="" disabled,确保默认选中状态正确。

内容的提问来源于stack exchange,提问作者Emilia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 05:40:24