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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 07:45:07