如何从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
相关产品推荐
相关产品推荐

