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

