React项目Firebase数据请求后调用setState,模板map方法不渲染问题
React项目Firebase数据拉取后map不渲染问题修复
核心问题
你的代码存在两处逻辑错误导致渲染异常:
- 异步时序错误:多层嵌套的Firebase异步请求没有全部完成就提前执行了
setSalesList和setIsLoading(false),此时存储数据的数组为空。后续customer.get()请求返回后直接向原数组push数据,没有触发React状态更新。 - 状态更新不符合不可变规则:React通过浅比较状态引用判断是否需要重渲染,直接修改原有数组内容(如push操作)不会改变数组引用地址,因此不会触发重渲染。
修复代码
将嵌套的回调写法改为async/await + Promise.all,等待所有异步请求完成后一次性更新状态,同时修正了原代码中月份少加1、渲染日期写死的小问题:
import React, { useState, useEffect } from "react"; import { Link } from "react-router-dom"; import NavBar from "./NavBar"; import { db } from "../firebase"; import { useAuth } from "../contexts/AuthContext"; const Sales = () => { const [isLoading, setIsLoading] = useState(true); const [salesList, setSalesList] = useState([]); const { currentUser } = useAuth(); async function setupProject() { try { // 逐层await异步请求,避免回调嵌套 const userItemData = await db.collection("users").doc(currentUser.uid).get(); const userItem = userItemData.data(); const projectData = await db.collection("projects").doc(userItem.project[0]).get(); const salesSnapshot = await db.collection("sales").where("project", "==", projectData.id).get(); // 用Promise.all等待所有customer请求完成 const salesPromiseArr = salesSnapshot.docs.map(async (sale) => { const saleData = sale.data(); const customer = await saleData.customer.get(); const time = saleData.time.toDate(); // getMonth返回0-11,加1才是实际月份 return { key: sale.id, name: customer.data().name, sold: saleData.sold, date: `${time.getDate()}.${time.getMonth() + 1}.${time.getFullYear()}` } }); // 所有请求完成后拿到完整数组,更新状态 const salesDataList = await Promise.all(salesPromiseArr); setSalesList(salesDataList); } catch (err) { console.error("数据拉取失败:", err); } finally { // 所有操作完成后再关闭加载状态 setIsLoading(false); } } useEffect(() => { // 增加currentUser存在性判断,避免未登录时报错 if (currentUser?.uid) { setupProject(); } }, [currentUser]); // 把currentUser加入依赖数组,用户切换时自动更新数据 return ( <> <NavBar /> <div className="header header-fixed header-logo-center"> <a className="header-title">Verkäufe</a> <a href="https://huehnerpi.de/customer" className="header-icon"> <i className="fas fa-user" /> </a> <a href="https://huehnerpi.de/sales/newSale" className="header-icon header-icon-4" > <i className="fas fa-plus" /> </a> </div> {isLoading ? ( <div className="page-content header-clear-medium"> <div className="content mt-0" style={{ marginBottom: 16, marginLeft: 16, marginRight: 16, }} > <p>Lädt...</p> </div> </div> ) : ( <div className="page-content header-clear-medium"> <div className="card card-style" style={{ marginBottom: "16px", }} > <div className="content mb-0"> <div className="input-style input-style-always-active has-borders no-icon"> <select id="dropdownStatus" style={{ color: "darkslategray", }} > <option value="all">Alle Status</option> </select> <span> <i className="fa fa-chevron-down" /> </span> <i className="fa fa-check disabled valid color-green-dark" /> <em /> </div> <div className="input-style input-style-always-active has-borders no-icon"> <select id="dropdownCustomer" style={{ color: "darkslategray", }} > <option value="all">Alle Käufer</option> </select> <span> <i className="fa fa-chevron-down" /> </span> <i className="fa fa-check disabled valid color-green-dark" /> <em /> </div> </div> </div> {salesList.map((saleItem) => ( <a key={saleItem.key} className="card card-style mb-3 filterDiv" style={{ display: "block" }} > <div className="content"> <h3> {saleItem.name} - {saleItem.sold} Eier <span data-menu="menu-contact-2" style={{ float: "right" }}> <span className="icon icon-xxs rounded-sm shadow-sm me-1 bg-red-dark"> <i className="fas fa-times" /> </span> </span> <span style={{ float: "right" }}> <span className="icon icon-xxs rounded-sm shadow-sm me-1 bg-blue-dark"> <i className="fas fa-pen" /> </span> </span> </h3> <div className="row mb-n2 color-theme"> <div className="col font-10 text-start"> <span className="badge bg-green-dark color-white font-10 mt-2"> Bezahlt </span> </div> <div className="col font-10 text-end opacity-30"> <i className="fa fa-calendar pe-2" /> {saleItem.date} </div> </div> </div> </a> ))} </div> )} </> ); }; export default Sales;
内容的提问来源于stack exchange,提问作者danielxheld
相关产品推荐
相关产品推荐

