Home > Software design >  setSate don't works in async function called in useEffect (React JS, Firestore)
setSate don't works in async function called in useEffect (React JS, Firestore)

Time:11-04

I'm trying to get a list of object from firestore and display them. Data are queried asynchroniously in firestore. When Data arrive, I can perfectly print them in console but when I try to do setQuestionList(data), questionList becomes null or empty.

const [questionListe, setQuestionListe] = useState(null);

//In useEffect
useEffect(()=>{
        const fetchD = async () => {
            const data = await getQuestionAll();
            setQuestionListe(data);
          }
        fetchD();
    }, []);
//My function for querying data in firestore
export async function getQuestionAll(){
    return new Promise(async resolve => {
        let liste = [];
        let questionsRef = collection(store, "questions");
        const q = query(questionsRef, orderBy("date", "desc"), limit(20));
        getDocs(q).then((snaps)=>{
            snaps.forEach(async (snap)=>{
                let obj = {
                    id: snap.id,
                    titre: snap.data().titre,
                    date: snap.data().date,
                    description: snap.data().description,
                    tags: snap.data().tags,
                    auteurID: snap.data().auteurID,
                    section: snap.data().section,
                    nbReponses: await getNbReponseForQuestion(snap.id)
                };
                liste.push(obj);
            });
            resolve(liste);
        })
    });
}

I have noticed that sometimes, when the user triggers another setState in the app, questionList updates himself immediately with the good values. It is like the updating is stuck by something.

CodePudding user response:

Have you tried putting the fetchD() function outside the useEffect and only calling it inside the useEffect rather than declaring and calling in the useEffect. Think best practice to declare the function outside of useEffect rather than declaring inside and also call inside.

const [questionListe, setQuestionListe] = useState(null);
 const fetchD = async () => {
            const data = await getQuestionAll();
            setQuestionListe(data);
          }

//In useEffect
useEffect(()=>{
       
        fetchD();
    });

CodePudding user response:

Since useState is asynchronous, it is very possible that first will render your component or return whatever it has to return, and only after will update the state (because of its asynchronous nature). The solution to that is a first render where you do expect null or undefined values (and set a placeholder instead) and afterwards there's a second render with the actual data.

From what you say, it seems that getQuestionAll works perfectly and the problem should be only with setting the state.

As the other answer suggests, also it is better practise to place the function outside, or I could also suggest to do an IIFE instead. Also, it is considered bad practice to leave the useEffect dependency array empty when it should actually store values.

In order to debug this issue, I would suggest to place debuggers or console.logs here:

useEffect(()=>{ const fetchD = async () => { const data = await getQuestionAll(); setQuestionListe(data); } fetchD(); }, []);

It would help to make the issue smaller to confirm if the data has successfully arrived when calling getQuestionAll (if that's so, then the problem is clearly not about the fetching).

  • Related