'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