Search code examples
reactjsreact-hooksrenderingfetch-api

useEffect Hook , API getting called twice


I am working on a Quiz App using React Context API. I used a useEffect hook for fetching quiz question data from an online API while using the start button state as a dependency. However, when I am console logging the extracted object data in Quiz.js, it seems the API is getting called twice despite the fact that I click the "Start Quiz" button only once (turning startQuiz state from false to true). Why is it happening? Also in the console, the logs from the child component (Quiz.js) are appearing first.

Code for App.js (Parent Component) ---->

import Quiz from "./Components/Quiz";
import { DataContext } from "./Context/DataContext";

export default function App() {

  const [startQuiz, setStartQuiz] = useState(false)

  const [quesList,setQuesList] = useState(null)


useEffect(()=> {

    let url = "https://opentdb.com/api.php?amount=5&difficulty=easy&type=multiple"

    fetch(url)
    .then(data => data.json())
    .then(data => { 
        setQuesList(data);
    }).catch(err => console.log(err))

    console.log(quesList)

  },[startQuiz])


  return (
    <div className="App">
      <div className="start-container">

              <h1 className="heading">General Knowledge Quiz</h1>
              <h5 className="sub-heading">Test your overall GK daily with these five questions</h5>
              <button 
                  className="startBttn"
                  onClick={()=> setStartQuiz(!startQuiz)}
                  >Start Quiz</button>
        <DataContext.Provider value={{quesList,setQuesList}}>
              {startQuiz && <Quiz/>}
        </DataContext.Provider>
      </div>
    </div>
  );
};

Code for Quiz.js (Child Component) ---->

import React ,{useContext} from 'react' 
import { DataContext } from '../Context/DataContext'


export default function Quiz() {
   
const {quesList} = useContext(DataContext)

  console.log(quesList)
  const question = quesList.results[0].question;
  console.log(question)
  const correct_answer = quesList.results[0].correct_answer;
  console.log(correct_answer)
  const incorrect_answers = quesList.results[0].incorrect_answers;
  console.log(incorrect_answers)


  return (
    <div>
        <h1>Quiz</h1>
    </div>
  )
}

</code>``` 

**What is the flow of the rendering here? Note: There is no "StrictMode" present in the code ( just found out that it can cause UseEffect to render twice) **

Solution

  • Whenever a state is being changed, your component is being re-rendered. Hence the reason your useEffect is called twice.

    I would suggest the following solution:

    Wrap your logic with an if statement

    useEffect(() => {
      if (startQuiz) {
        let url =
          "https://opentdb.com/api.php?amount=5&difficulty=easy&type=multiple";
    
        fetch(url)
          .then((data) => data.json())
          .then((data) => {
            setQuesList(data);
          })
          .catch((err) => console.log(err));
    
        console.log(quesList);
      }
    }, [startQuiz]);