'When I try to setState in useEffect it doesnt work
After getting the documents I want and storing as objects in an array shown here
const appealsRef = collection(db, "appeals");
const today = new Date();
const getAppeals = async (logicalOp) => {
const q = query(appealsRef, where("toDate", logicalOp, convertDateToTimestamp(today)))
const querySnapshot = await getDocs(q);
let dummyAppeals = [];
querySnapshot.docs.map((doc) => {
const docData = { ...doc.data() };
getOrgByDocID(docData.orgDocID)
.then((res) => {
const appealData = {
...docData,
orgName : res.orgName,
orgAddress : res.orgAddress
}
dummyAppeals.push(appealData)
})
});
return dummyAppeals
}
I would like to set the results in state variables currentAppeals and pastAppeals based on the logicalOp given in useEffect and then set it into another state variable array appeals using setAppeals; this is because depending on what the user clicks on which is past or present I would like to set the appeals array to currentAppeals if present is clicked or pastAppeals if past is clicked.
The code involved :
const [ currentAppeals, setCurrentAppeals ] = useState([]);
const [ appeals, setAppeals ] = useState([]);
useEffect(() => {
getAppeals(">=")
.then((res) => {
setCurrentAppeals(res);
setAppeals(currentAppeals.map((appeal, i) => {
return (
<AppealCard
appealID={appeal.appealID}
from={appeal.fromDate}
to={appeal.toDate}
orgName={appeal.orgName}
orgAddress={appeal.orgAddress}
outcome={appeal.outcome}/>
)
}));
});
}, []);
And then I will display the appeals in the react component here :
<div className='view-appealsBody'>
{
appeals
}
</div>
But the appeals are not set after setAppeals in useEffect().
Solution 1:[1]
Check this out
// const [ currentAppeals, setCurrentAppeals ] = useState([]);
const [ appeals, setAppeals ] = useState([]);
useEffect(() => {
getAppeals(">=")
.then((res) => {
// setCurrentAppeals(res);
setAppeals(res.map((appeal, i) => {
return (
<AppealCard
appealID={appeal.appealID}
from={appeal.fromDate}
to={appeal.toDate}
orgName={appeal.orgName}
orgAddress={appeal.orgAddress}
outcome={appeal.outcome}/>
)
}));
});
}, []);
Solution 2:[2]
you must set appeals as second parameter in useEffect
useEffect(() => {
getAppeals(">=")
.then((res) => {
setCurrentAppeals(res);
});
}, [appeals]);
and better put this code to return the body of component
currentAppeals.map((appeal, i) => {
return (
<AppealCard
appealID={appeal.appealID}
from={appeal.fromDate}
to={appeal.toDate}
orgName={appeal.orgName}
orgAddress={appeal.orgAddress}
outcome={appeal.outcome}/>
)
});
Solution 3:[3]
It happens because React setState is an asynchronous function. You're setting appeals using previously set state i.e currentAppeals. Instead of try to set it using res only like:
const [ currentAppeals, setCurrentAppeals ] = useState([]);
const [ appeals, setAppeals ] = useState([]);
useEffect(() => {
getAppeals(">=")
.then((res) => {
setCurrentAppeals(res);
setAppeals(res.map((appeal) => {
return (
<AppealCard
key={appeal.appealID}
appealID={appeal.appealID}
from={appeal.fromDate}
to={appeal.toDate}
orgName={appeal.orgName}
orgAddress={appeal.orgAddress}
outcome={appeal.outcome}/>
)
}));
});
}, []);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ali Hussnain |
| Solution 2 | Arash Ghazi |
| Solution 3 | Harsh Patel |
