I am making a small weather app using React. I intend to use the useState
hook for an array of objects. Through an array of objects - latLongStore
, I make multiple axios get
calls to fetch weather data for different cities. The fetch part works well but weatherData
values do not show up in the DOM. It has the correct number of objects but appears to contain no values. Below is my code:
...
const latLongStore = [
{ latitude: 23.8315, longitude: 91.2868, title: "Agartala", color: "#299617", code: 'VEAT' },
{ latitude: 23.0225, longitude: 72.5714, title: "Ahmedabad", color: "#299617", code: 'VCBI' },
...
]
const initialData = {
city: '',
latitude: 0,
longitude: 0,
max_temperature: 0,
min_temperature: 0
}
function TableView(props) {
const [weatherData, updateWeatherData] = useState([initialData]);
useEffect(() => {
latLongStore.forEach((latLong) => {
axios.get(`api-url`).then((response) => {
const fetchedData = {
city: latLong.title,
latitude: response.data.latitude,
longitude: response.data.longitude,
max_temperature: response.data.daily.temperature_2m_max[0],
min_temperature: response.data.daily.temperature_2m_min[0]
}
console.log(fetchedData);
updateWeatherData(weatherData => [...weatherData, fetchedData]);
})
})
}, []);
switch (weatherData.length) {
default:
return (
<div>
<br />
<br />
<br />
<br />
LOADING...
{weatherData.length}
</div>
)
// weatherData contains 62 objects after fetch but no values show up in DOM
case 62:
return (
<div>
<br />
<br />
<br />
<br />
{ weatherData.forEach((data) => {
<div>
{ data.city } : { data.latitude }, { data.longitude }
</div>
}) }
</div>
)
// default:
// return (
// <div>
// <br />
// <br />
// <br />
// <br />
// LOADING...
// </div>
// )
}
}
export default TableView;
Here's the output:
- At a particular instant of updation
Can someone tell me how I can show up weatherData
values in DOM.
CodePudding user response:
Your forEach
function is actually doing nothing there. It's just looping through an array and that's all. You need to use Array.map()
and make the callback function return something. Like this (not tested):
{
weatherData.map((data) => {
return (<div>
{data.city} : {data.latitude}, {data.longitude}
</div>)
})
}
CodePudding user response:
Note: I've removed the API request in the snippet as otherwise the snippet wouldn't work. (You can obviously put that back inside the useEffect
)
I would recommend you don't depend on the length of the resultant array. But rather focus on if the request(s) are loading or not.
const { useState, useEffect } = React;
const latLongStore = [{
latitude: 23.8315,
longitude: 91.2868,
title: "Agartala",
color: "#299617",
code: 'VEAT'
},
{
latitude: 23.0225,
longitude: 72.5714,
title: "Ahmedabad",
color: "#299617",
code: 'VCBI'
}
]
// const initialData = {
// city: '',
// latitude: 0,
// longitude: 0,
// max_temperature: 0,
// min_temperature: 0
// }
function TableView(props) {
const [weatherData, updateWeatherData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
// Set Loading to true before requests
setIsLoading(true);
latLongStore.forEach((latLong) => {
// I have removed the request as I can't access whatever API being used
const fetchedData = {
city: latLong.title,
latitude: latLong.latitude,
longitude: latLong.longitude,
max_temperature: 5,
min_temperature: 2
};
// console.log(fetchedData);
updateWeatherData(weatherData => ([
...weatherData,
fetchedData
]));
})
// Set Loading to false after
setIsLoading(false);
}, []);
if (isLoading) {
return (
<div >
<br />
<br />
<br />
<br />
LOADING...{weatherData.length}
</div>
)
}
return (
<div>
<br />
<br />
<br />
<br />
{weatherData.map((data, index) => (
<div key={index}>
{data.city}, {data.latitude}, {data.longitude}
</div>
))}
</div>
)
}
ReactDOM.render(
<TableView /> ,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>