Home > Blockchain >  useState not working for array of objects
useState not working for array of objects

Time:10-26

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

enter image description here

  • After the weatherData.length reaches 62
    enter image description here

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>

  • Related