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

如何从Firebase Firestore获取数据并存入useState及解决映射问题

问题描述

已成功从Firebase获取所有docs并能在控制台打印数据,但列表映射存在问题。核心原因是API请求是异步的,组件渲染时映射函数会立即执行,此时数据还未返回,导致无数据可处理。需要等待数据返回后,将数组存入React的useState中。

原代码如下:

GetAllGoals 文件

import { firebaseDB } from "./db";
import { collection, getDocs } from "firebase/firestore";

const responseArr: any[] = [];

// GETS ALL AVAILABLE DOCS IN GOALs COLLECTION
const getAllGoals = async () => {
  const response = await getDocs(collection(firebaseDB, "goals"));
  response.forEach((doc) => {
    responseArr.push(doc.data());
  });
};

export { getAllGoals, responseArr };

GoalList 组件

import React, { useEffect, useState } from "react";
import OnprogressGoals from "./OnprogressGoals";
import GoalsDone from "./GoalsDone";
import { getAllGoals, responseArr } from "../../containers/GetAllGoals";

const GoalList = (props: any) => {
  const [refresh, setrefresh] = useState([]);
  useEffect(() => {
    getAllGoals();
    responseArr.map((goal) => {
      const goaler: any = [...refresh, goal];
      setrefresh(goaler);
    });
  }, []);

  console.log(refresh);

  const OnprogressGoalsResponse = responseArr.filter(
    (Goal) => Goal.GoalCompletion === "Onprogress"
  );

  const GoalsDoneResponse = responseArr.filter(
    (Goal) => Goal.GoalCompletion === "Done"
  );
  return (
    <div className="h-[85%] overflow-y-scroll scrollbar-thin scrollbar-thumb-gray-900 scrollbar-track-gray-50">
      <button onClick={() => alert("I am clicked")}>click me</button>
      <table className="w-full h-full">
        <>
          <tr className="border-b px-5">
            <td className="text-sm font-medium py-5 pl-5">
              <span>Date created</span>
            </td>
            <td className="text-sm font-medium py-5">
              <span className="border-l pl-3">Goal name</span>
            </td>
            <td className="text-sm font-medium py-5">
              <span className="border-l pl-3">Due date</span>
            </td>
            <td className="text-sm font-medium py-5 pr-5">
              <span className="border-l pl-3">Goal target</span>
            </td>
          </tr>
          <tr>
            <td colSpan={4} className="px-5">
              <h1 className="py-5 font-semibold text-2xl">On progress</h1>
            </td>
          </tr>
          <OnprogressGoals
            ShowGoalDetail={props.ShowGoalDetail}
            goalsList={OnprogressGoalsResponse}
          />
          <tr>
            <td colSpan={4} className="px-5">
              <h1 className="py-5 font-semibold text-2xl">Goal done</h1>
            </td>
          </tr>
          <GoalsDone
            ShowGoalDetail={props.ShowGoalDetail}
            goalsList={GoalsDoneResponse}
          />
        </>
      </table>
    </div>
  );
};

export default GoalList;
解决方案

1. 重构数据获取函数

修改GetAllGoals文件,让异步函数直接返回目标数组,移除全局变量避免状态不同步:

import { firebaseDB } from "./db";
import { collection, getDocs } from "firebase/firestore";

// 获取goals集合下所有文档并返回数组
const getAllGoals = async () => {
  const response = await getDocs(collection(firebaseDB, "goals"));
  return response.docs.map(doc => doc.data());
};

export { getAllGoals };

2. 优化组件状态管理

修改GoalList组件,在useEffect中等待异步请求完成后更新状态,所有数据逻辑基于组件内部状态:

import React, { useEffect, useState } from "react";
import OnprogressGoals from "./OnprogressGoals";
import GoalsDone from "./GoalsDone";
import { getAllGoals } from "../../containers/GetAllGoals";

const GoalList = (props: any) => {
  // 用状态存储所有目标数据
  const [allGoals, setAllGoals] = useState<any[]>([]);

  useEffect(() => {
    // 封装异步逻辑,等待数据返回后更新状态
    const fetchGoals = async () => {
      const goals = await getAllGoals();
      setAllGoals(goals);
    };
    fetchGoals();
  }, []);

  // 基于状态数据筛选,确保数据就绪后执行
  const OnprogressGoalsResponse = allGoals.filter(
    (goal) => goal.GoalCompletion === "Onprogress"
  );

  const GoalsDoneResponse = allGoals.filter(
    (goal) => goal.GoalCompletion === "Done"
  );

  return (
    <div className="h-[85%] overflow-y-scroll scrollbar-thin scrollbar-thumb-gray-900 scrollbar-track-gray-50">
      <button onClick={() => alert("I am clicked")}>click me</button>
      <table className="w-full h-full">
        <>
          <tr className="border-b px-5">
            <td className="text-sm font-medium py-5 pl-5">
              <span>Date created</span>
            </td>
            <td className="text-sm font-medium py-5">
              <span className="border-l pl-3">Goal name</span>
            </td>
            <td className="text-sm font-medium py-5">
              <span className="border-l pl-3">Due date</span>
            </td>
            <td className="text-sm font-medium py-5 pr-5">
              <span className="border-l pl-3">Goal target</span>
            </td>
          </tr>
          <tr>
            <td colSpan={4} className="px-5">
              <h1 className="py-5 font-semibold text-2xl">On progress</h1>
            </td>
          </tr>
          <OnprogressGoals
            ShowGoalDetail={props.ShowGoalDetail}
            goalsList={OnprogressGoalsResponse}
          />
          <tr>
            <td colSpan={4} className="px-5">
              <h1 className="py-5 font-semibold text-2xl">Goal done</h1>
            </td>
          </tr>
          <GoalsDone
            ShowGoalDetail={props.ShowGoalDetail}
            goalsList={GoalsDoneResponse}
          />
        </>
      </table>
    </div>
  );
};

export default GoalList;

关键改进点

  • 移除全局变量responseArr,改为异步函数直接返回数据,避免跨模块状态不同步
  • 在useEffect中封装异步请求,确保数据返回后才更新组件状态
  • 所有筛选逻辑基于组件内部状态allGoals,保证数据就绪后才执行映射/筛选操作
  • 避免循环调用setState的错误写法,减少不必要的组件重渲染

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 10:01:20