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.