I am fetching all docs
from firebase, I did it successfully, I can even log it in console.
Mapping through the list is the problem.
The fetch API takes time before it returns the data, while my map function runs immediately after the components were invoke, at that moment the API didn't return anything, so map function will have nothing to map.
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 };
Now all I want is to wait for response then store it array in in useState()
.
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>
{/* {console.log(`Goal List - ${props.goalsList}`)} */}
<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;
CodePudding user response:
That's right because the responseArr
doesn't waiting for getAllGoals.
Try this:
useEffect(() => {
getDocs(collection(firebaseDB, "goals")).then((response) => {
response.forEach((goal) => {
const goaler: any = [...refresh, goal];
setrefresh(goaler);
}
}
);
}, []);
CodePudding user response:
Your dependency array is empty that why useEffect is called only once after the render and your component cannot render the update data in responeArr. So to call it when data is load put your responseArr as dependancy in the useEffect. Just update your useEffect with the below code
useEffect(() => {
getAllGoals();
responseArr&&responseArr.map((goal) => {
const goaler: any = [...refresh, goal];
setrefresh(goaler);
});
}, [responseArr]);
CodePudding user response:
remove responseArr and use responseArr as useState(), I hope that help you
const responseArr: any[] = []; // it not update your component after rendeing component
let ArrEmpWithType : Array<any> = []
const GoalList = (props: any) => {
const [responseArr, setresponseArr] = useState(ArrEmpWithType);
const [refresh, setrefresh] = useState([]);
const getAllGoals = async () => {
const response = await getDocs(collection(firebaseDB, "goals"));
response.forEach((doc) => {
let Mydoc: any = doc.Data();
Mydoc.id = doc.id;
setresponseArr([...responseArr, Mydoc])
});
};
useEffect(() => {getAllGoals(); }, []);
useEffect(() => { }, [responseArr]);// it help rerender after update responseArr