Ali
Ali

Reputation: 113

First fetching data is successfull, second fetching not

I want to fetch data with useEffect. With the first function, I get event details and with the second function, I get questions, which are related to the event (by ID). Fetching data for the event is successful, but second fetching data for the questions is not successful (sometimes is successful). Why fetching data once is successful, but the second time is not successful?

The output of console log:

Quiz.js:23 {active: true, _id: "6012eafe7813901034e77fb3", nameOfEvent: "Udalost 3", creatorId: "5fd23fb7b1a3a005cc82225d", participants: Array(0), …}

Quiz.js:45 {}

Quiz.js:23 {active: true, _id: "6012eafe7813901034e77fb3", nameOfEvent: "Udalost 3", creatorId: "5fd23fb7b1a3a005cc82225d", participants: Array(0), …}active: truecodeEvent: "udalost1"createdAt: "2021-01-28T16:49:02.374Z"creatorId: "5fd23fb7b1a3a005cc82225d"nameOfEvent: "Udalost 3"participants: []updatedAt: "2021-02-01T16:52:45.471Z"__v: 0_id: "6012eafe7813901034e77fb3"__proto__: Object

Quiz.js:45 {}

File Quiz.js

const Quiz = () => {
    const dataForQuiz = getUserDataToQuiz();
    const [eventValues, setEventValues] = useState({});
    const [questionBankOfEvent, setQuestionBankOfEvent] = useState({});

    const initDataToEvent = () => {
        getEventByEventCode(dataForQuiz.codeEvent).then(data => {
            if (!data.error) {
                setEventValues(data);
            }
            else {
                console.log(data.error);
            }
        })
    }

    console.log(eventValues);
    
    const initQuestionsForQuiz = () => {
        if (eventValues) {
            getQuestionsToEvent(eventValues._id).then((data) => {
                if (!data.error) {
                    setQuestionBankOfEvent(data);
                }
                else {
                    console.log(data.error);
                }
            })
        }
    }

    useEffect(() => {
        initDataToEvent();
        if(eventValues){
           initQuestionsForQuiz(); 
        }
    }, []);

    console.log(questionBankOfEvent);

    const formQuiz = () => {
        return(
            <>
                <h1>Quiz</h1>
            </>
        );
    }

    return (
        <>
            {formQuiz()}
        </>
        
    );
}

export default Quiz;

Upvotes: 2

Views: 48

Answers (2)

Mvrocha
Mvrocha

Reputation: 403

Probably, due to the fact that both are in the same useEffect, since react doesn´t update useState instantly. I would separate them in two different useEffect, being:

 useEffect(() => {
        initDataToEvent();
    }, []);
   
   useEffect(() => {
         if(eventValues){
           initQuestionsForQuiz(); 
        }
    }, [eventValues]);
   

Upvotes: 1

RobBlanchard
RobBlanchard

Reputation: 905

On the first render of your component, you execute

initDataToEvent();
if(eventValues){
   initQuestionsForQuiz(); 
}

initDataToEvent is supposed to update eventValues. So you expect initQuestionsForQuiz to be executed.
But, by the time if(eventValues) is evaluated, setEventValues has been fired, but the eventValues state has not been modified yet.
Hence, if you modify your code to:

useEffect(() => {
    initDataToEvent();
    console.log(eventValues);
    if(eventValues){
       initQuestionsForQuiz(); 
    }
}, []);

You would observe eventValues to be empty.

In React, it is best practice to split events and logic. In your case, you want initQuestionsForQuiz to be run when eventValues has been updated and not empty. Modifying your code to:

useEffect(() => {
    initDataToEvent();
}, []);

useEffect(() => {
    if(eventValues){
       initQuestionsForQuiz(); 
    }
}, [eventValues]);

should make it work. What this code does is that the function given as argument to the seconde useEffect will be run every time eventValues is modified.

Upvotes: 2

Related Questions