onapte
onapte

Reputation: 267

useState not working for array of objects

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:

enter image description here

Can someone tell me how I can show up weatherData values in DOM.

Upvotes: 0

Views: 119

Answers (2)

DINO
DINO

Reputation: 196

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>)
  })
}

Upvotes: 1

Harrison
Harrison

Reputation: 2347

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>

Upvotes: 0

Related Questions