Home > Software engineering >  UseEffect mutiple re-renders after async api call and make changes in UI after 1 sec of first call
UseEffect mutiple re-renders after async api call and make changes in UI after 1 sec of first call

Time:08-01

I'm making a Quiz app, using API from (Trivia api), Issues is - As soon as the api call is made the state is changes 3 times and my UI data changes 2 times in 1 second. I think the issue is related to useEffect even though i'm adding empty dependency in useEffect. can anybody explain why is it happening?

Layout.js

import { useEffect, useState } from 'react'
import { Outlet } from 'react-router-dom'
import Header from '../Componenets/Header/Header'
import ProgressBar from '../Componenets/ProgressBar/ProgressBar'
import QuizMain from '../Componenets/QuizMain/QuizMain'

function Layout() {
  const [questionAre, setQuestionsAre] = useState([])
  const [currentQuestion, setCurrentQuestion] = useState(0)

  const changeCurrentQuestion = (value) => {
    setCurrentQuestion(value)
  }

  useEffect(() => {
    const QuizFetch = async () => {
      try {
        const res = await fetch(
          'https://the-trivia-api.com/api/questions?categories=food_and_drink,general_knowledge&limit=10&region=AU&difficulty=easy',
        )
        const data = await res.json()

        const transformData = data.map((item) => {
          const newarray = item.incorrectAnswers

          return {
            options: newarray,
            question: item.question,
            correctAnswer: item.correctAnswer,
          }
        })

        setQuestionsAre(transformData)
      } catch (err) {
        console.log(err, 'err in getting data')
      }
    }

    QuizFetch()
  }, [])

  return (
    <div className="Layout">
      <Header />
      <ProgressBar
        changeCurrentQuestion={changeCurrentQuestion}
        currentQuestion={currentQuestion}
        questionAre={questionAre}
      />
      {/* <QuizMain
            changeCurrentQuestion={changeCurrentQuestion}
            currentQuestion={currentQuestion}
            questionAre={questionAre} /> */}

      <Outlet context={[changeCurrentQuestion, currentQuestion, questionAre]} />
    </div>
  )
}

export default Layout

CodePudding user response:

Since react 18 and the lifecycle in dev mode you have to use the abortController. The signal will jump to the catch and then you will only have one successfull api call

useEffect(() => {
    const abortController = new AbortController();

    const QuizFetch = async () => {
      
      try {
        const res = await fetch(
          'https://the-trivia-api.com/api/questions?categories=food_and_drink,general_knowledge&limit=10&region=AU&difficulty=easy',
          {
            signal: abortController.signal,
          },
        )
        const data = await res.json()

        const transformData = data.map((item) => {
          const newarray = item.incorrectAnswers

          return {
            options: newarray,
            question: item.question,
            correctAnswer: item.correctAnswer,
          }
        })

        setQuestionsAre(transformData)
      } catch (err) {
        if (abortController.signal.aborted) return;
        console.log(err, 'err in getting data')
      }
    }

    QuizFetch()
    
     return () => {
      abortController.abort();
    };
  }, [])

  • Related