Home > Software engineering >  Why is this useEffect causing an infinite loop of requests to '/analysis api on the backend
Why is this useEffect causing an infinite loop of requests to '/analysis api on the backend

Time:07-24

This is the backend node.js route

app.post('/analysis' , async (req , res) => {
  const {temp , humidity} = req.body.data.current

  let predictedCrops:any[] = []
  let humidityDiffernece1 
  let humidityDiffernece2
  let tempDifference1
  let tempDifference2

 //Getting all crops and optimums from databse so they are in an array (Easier to work with)
const data = await CropOptimum.find({})
  
  data.map(({name , min_optimum_temp , max_optimum_temp , min_optimum_humidity , max_optimum_humidity }) => {
    if(temp >= min_optimum_temp && temp <= max_optimum_temp && humidity >= min_optimum_humidity && humidity <= max_optimum_humidity) {
      const data = {
        name: name,
        msg: 'Perfect Temperature and Humidity for this crop'
      }
      predictedCrops.push(data)
      // console.log(`Perfect Match ${name}`)
    } else if (temp >= min_optimum_temp && temp <= max_optimum_temp && humidity <= min_optimum_humidity) {
      humidityDiffernece1 = min_optimum_humidity - humidity
      // console.log(`Humidity is less than minimum and difference is ${humidityDiffernece1}`)
    } else if (temp >= min_optimum_temp && temp <= max_optimum_temp && humidity >= max_optimum_humidity ) {
      humidityDiffernece2 = humidity - max_optimum_humidity
      // console.log(`Humidity is more than maximum and difference is ${humidityDiffernece2}`)
    } else if(humidity >= min_optimum_humidity && humidity <= max_optimum_humidity && temp <= min_optimum_temp) {
        tempDifference1 = min_optimum_temp - temp
        // console.log(`Temperature is less than minimum , difference is ${tempDifference1}`)
    } else if(humidity >= min_optimum_humidity && humidity <= max_optimum_humidity && temp >= max_optimum_temp) {
        tempDifference2 = temp - max_optimum_temp
        // console.log(tempDifference2)
    } else {
      // console.log("NO MATCHES")
    }
  })
  console.log(predictedCrops)
  res.send(predictedCrops)
})

This is where I call the API or make the request to /analysis in react frontend

useEffect( () => {
        navigator.geolocation.getCurrentPosition((postion) => {
            setLatitiude(postion.coords.latitude)
            setLongitude(postion.coords.longitude)
        })

        getWeatherDetails()
    }, [isAnalyzing , predictedCrop])

This is the getWeatherDetails function

const getWeatherDetails = async() => {
        try {
            const response = await axios.get(`${API_ENDPOINT}lat=${latitude}&lon=${longitude}&exclude=hourly,daily&units=metric&appid=${API_KEY}`)
            console.log(response.data)
            
            //Send temp and humidity to backend for analysis
            const dataToSend = response.data
            const sentWeatherData = await axios.post("http://localhost:4000/analysis" , {
                data: dataToSend
            }).then((response) => {
                let dataObject = response.data;
                setPredictedCrop(dataObject)
                console.log(predictedCrop)
            })

        } catch {
            console.log("error")
        }
    }

So basically, what is happening is that when a button is clicked it sets isAnalyzing state to true and the process starts. When I remove predictedCrop from the dependency it does not cause the loop however the predictedCrop state will not update on the line where it says setPredictedCrop(dataObject). When I add the predictedCrop to the dependency of the useEffect it causes the loop but sets the state successfully.

I am kind of a beginner at this so any help is appreciated, thank you.

CodePudding user response:

When I remove predictedCrop from the dependency it does not cause the loop however the predictedCrop state will not update on the line where it says setPredictedCrop(dataObject). When I add the predictedCrop to the dependency of the useEffect it causes the loop but sets the state successfully.

You got the wrong concept here. Mentioning a state variable or a prop in a dependency array is not a necessity for the state variable or a prop value to change. It denotes that any changes to that value will trigger the useEffect.

In your case, if predictedCrop, is not in the dependency array, it's state will change, it's just that, it won't trigger the useEffect, whenever it's updated. Putting it in the array, will trigger the useEffect and will cause infinite loop.

CodePudding user response:

The reason the console.log's are empty is because react state setting is asynchronous. It's probably setting it fine, it just happens shortly after the console.log because of how React batches state updates and runs them later seamlessly.

I would suggest logging it in the render method or something.

See here for more details: https://beta.reactjs.org/apis/usestate#ive-updated-the-state-but-logging-gives-me-the-old-value.

So removing predictedCrop from deps array is fine, its just your logging is confusing you :).

Its worth noting however you probably should not be doing the network call in the useEffect anyway. It would be better to do it in the event handler of the button itself. useEffect is for side effects, and this isnt one -- its in response to button click.

See here https://beta.reactjs.org/learn/synchronizing-with-effects#not-an-effect-buying-a-product

You wouldn’t want to buy the product twice. However, this is also why you shouldn’t put this logic in an Effect. What if the user goes to another page and then presses Back? Your Effect would run again. You don’t want to buy the product when the user visits a page; you want to buy it when the user clicks the Buy button.

  • Related