Kivuos
Kivuos

Reputation: 13

Infinite loop in React

function QuestionAns(){
    const url = 'http://127.0.0.1:8000/'
    const [data, setData] = useState([]);
    const [currData, setCurrData] = useState([])
    let i = 1

    useEffect(() => {
        let result = []
        const fetchFromUrl = async() => {
            const response = await axios.get(url)
            const response_data = await response.data.data
            await setData(response_data)
        }

        fetchFromUrl()
    }, [])

    const run_loop = async ()=>{
        let arr = []

        for(let counter = 0; counter < 12; counter++){
            arr.push(<Pretty count={i} question={data[i].question} answer_option={data[i].option_arr} answer={data[i].answer} key={data[i]._id} corr_ans={data[i]._id}/>)
            i+=1
        }

        let dat = await arr.concat(currData)
        await setCurrData(dat)
    }

    if(data.length){
        run_loop()
    }

    return (
        <div className="container my-3">
            <div className="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-5">
                {data.length ? currData : `loading`}
            </div>
        </div>
    )
}

export default QuestionAns;

In this function fetchFromUrl we are getting the data from the server which is stored in the data state again I am taking 12 data from the fetched content and storing it to currData. Purpose is to make a infinite scroll. but if I keep the code like that I am getting a infinite entries of 12 data means 1 to 12 -> 1 to 12 -> 1 to 12 ..... . Problem lies with currData.

Any idea why I am getting in this infinite loop. I am good with raw js and can do this this easily but I am learning react now so any help will be appriciated.

Problem screenshot

I was expecting the data from 1-12 will load single time.

Upvotes: 0

Views: 162

Answers (1)

Ahmed Sbai
Ahmed Sbai

Reputation: 16169

if(data.length){
    run_loop()
}

this condition is always true expect for the first render before running useEffect but once fetchFromUrl() is executed data.length become true forever since inside this function you are updating the useState hook

setData(response_data)

if(data.length) returns true if data.length > 0 which is always the case unless response.data.data is an empty array

after what happens ? run_loop() executes and updates currData

setCurrData(dat)

and this will re-render the component and since if(data.length)is always true this will happen infinitely.

so I guess you are getting an infinite render not an infinite loop. try to console.log from inside your jsx to be sure

return (
  <div className="container my-3">
  {console.log('this is a new render')}
     <div className="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-5">
       {data.length ? currData : `loading`}
     </div>
   </div>
)

what you should do is to make run_loop() part of fetchFromUrl so it runs inside useEffect I don't understand but this is what your code is doing if(data.legth){run_loop()}

    useEffect(() => {
        let result = [];
        let arr = []
        const fetchFromUrl = async() => {
            const response = await axios.get(url)
            const response_data = response.data.data
            setData(response_data)
            if(response_data.length > 11){ // this is better
              for(let counter = 0; counter < 12; counter++){
                arr.push(<Pretty count={i} question={response_data[i].question} answer_option={response_data[i].option_arr} answer={response_data[i].answer} key={response_data[i]._id} corr_ans={response_data[i]._id}/>)
                i+=1
                }
              let dat = arr.concat(currData)
              setCurrData(prevState => {
              if(prevState.length === dat.length) {return prevState} else {return dat} // this will avoid the infinite render
              })
            }
        }
        fetchFromUrl()
    }, [])

NOTE ALSO : you need the await key only in this line

const response = await axios.get(url) 

Upvotes: 1

Related Questions