1

I am using axios to fetch weather api data with useEffect.

import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { Header } from './Header';

export const CurrentCity = () => {
  const [weather, setWeather] = useState({});

  console.log('weather', weather);
  console.log(weather.weather[0].icon);

  useEffect(() => {
    async function getData() {
      const url = `https://api.openweathermap.org/data/2.5/weather?q=Berlin&appid=${process.env.REACT_APP_WEATHER_KEY}`;
      try {
        const response = await axios.get(url);
        setWeather(response.data);
      } catch (err) {
        console.log(err);
      }
    }
    getData();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  return (
    <div>
      <Header api={weather} />
    </div>
  );
};

This is the result of console.log(data) :

{coord: {…}, weather: Array(1), base: "stations", main: {…}, visibility: 10000, …}
coord: {lon: 13.41, lat: 52.52}
weather: Array(1)
0: {id: 802, main: "Clouds", description: "scattered clouds", icon: "03n"}
length: 1
__proto__: Array(0)
base: "stations"
main: {temp: 278.43, feels_like: 270.3, temp_min: 276.48, temp_max: 280.37, pressure: 1009, …}
visibility: 10000
wind: {speed: 8.7, deg: 270, gust: 13.9}
clouds: {all: 40}
dt: 1584060559
sys: {type: 1, id: 1275, country: "DE", sunrise: 1584077086, sunset: 1584119213}
timezone: 3600
id: 2950159
name: "Berlin"
cod: 200
__proto__: Object

If I console.log the data I am getting by

console.log('weather', weather);

console.log(weather.weather[0].icon);

the error messages says, it cannot read the property of [0],

or if I try to access deeper into 'wind' for example,

 console.log(weather.wind.speed);

it says, cannot read the property of speed.

If it is an array that I want to have access to, I would use [0] or if it's an object, I would use dot notation.

Moreover I am passing down the data which I got from axios to Header.js

import React from 'react';

export const Header = props => {
  console.log(props.api.name);
  return (
    <div>
      <h1>{props.api.name}</h1>
    </div>
  );
};

Same thing happens when I try to go deeper into the other data.

I would like to find out what I am missing, Thank you all in advance! And also want to know what the difference is between 1 and 2, and which one should I be using for current situation.

  1. const [weather, setWeather] = useState({});
  2. const [weather, setWeather] = useState(null);
  • When you call `console.log(weather.weather[0].icon);`, the weather is just initialize to `{}`, so you see the error message in console. – sam Mar 13 '20 at 02:55
  • The difference in 1 and 2 is that `weather` is initialized as `{}` in the 1st and `null` in the 2nd – Dev Mar 13 '20 at 03:02
  • @JongHyeokLee also see https://stackoverflow.com/help/someone-answers – Junius L Mar 14 '20 at 07:39

2 Answers2

1

Your code is correct but as the guys said, the weather object will initially set to empty object {} so you just need to check it first.

const App = () => {

  const [weather, setWeather] = useState(null) // change it to null for easier check

  // useEffect() ...

  if (!weather) {
    return <div>Loading indicator</div>
  }

  return (
    <div className="App">
      <Header api={weather} />
    </div>
  )
}

Edit romantic-bartik-9oyk3

awran5
  • 4,333
  • 2
  • 15
  • 32
  • I think the problem is here ```console.log('weather', weather); console.log(weather.weather[0].icon);``` PO is logging something that doesn't exist. – Junius L Mar 13 '20 at 09:03
  • please see https://codesandbox.io/s/dreamy-framework-2we54?fontsize=14&hidenavigation=1&theme=dark – Junius L Mar 13 '20 at 09:11
  • Yes, I see that but from what i understand the main issue that he couldn't read the data from `Header` component so he tried to `log` it. Remove the that `log` and the return check you'll get the same error. – awran5 Mar 13 '20 at 09:15
  • @JuniusL. [here](https://codesandbox.io/s/smoosh-violet-6k54f) is what i mean, would you please show your solution if I'm wrong? – awran5 Mar 13 '20 at 09:32
  • I'm not saying you are wrong, I was just saying the console error where because OP was trying to access a property that didn't exists. – Junius L Mar 13 '20 at 09:39
  • @JuniusL. So why the downvote? Your second approach is just about what i did. – awran5 Mar 13 '20 at 10:17
  • Oh, sorry then, nvm, I thought so because I got it after your first comment. – awran5 Mar 13 '20 at 10:21
  • Thank you people! Helped me fix my code! Thanks a lot! – JongHyeok Lee Mar 13 '20 at 13:37
  • 1
    @JongHyeokLee Thank you. Actually **JuniusL** answer' has better approach, you may want to use loading indicator and error handling in your app as he posted. – awran5 Mar 13 '20 at 14:17
1

You are getting that error because you are trying to access a key that doesn't exist in the object. In the following weather is set to an empty object.

// remove this from your code
console.log('weather', weather);
// this will throw an error, since weather is an empty object.
console.log(weather.weather[0].icon);

import React, { useEffect, useState } from "react";
import axios from "axios";
import { Header } from "./Header";

export const CurrentCity = () => {
  const [weather, setWeather] = useState({});

  useEffect(() => {
    async function getData() {
      const url = `https://api.openweathermap.org/data/2.5/weather?q=Berlin&appid=${
        process.env.REACT_APP_WEATHER_KEY
      }`;
      try {
        const response = await axios.get(url);
        setWeather(response.data);
      } catch (err) {
        console.log(err);
      }
    }
    getData();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  return (
    <div>
      <Header api={weather} />
    </div>
  );
};

Then in your header validate your data, don't assume that you'll always get the right data.

import React from "react";

export const Header = props => {
  console.log(props);
  return (
    <div>
      {/* here validate your data */}
      <h1>{props && props.api && props.api.name}</h1>
    </div>
  );
};

You can also add a loader to show the user that you are fetching data from the server.

export const CurrentCity = () => {

  const [weather, setWeather] = useState({});
  const [isLoading, setIsLoading] = useState(true);
  const [isError, setIsError] = useState(false);

  useEffect(() => {

    async function getData() {

      const url = `https://api.openweathermap.org/data/2.5/weather?q=Berlin&appid=${
        process.env.REACT_APP_WEATHER_KEY
      }`;
      try {

        const response = await axios.get(url);
        setWeather(response.data);
        setIsLoading(false);

      } catch (err) {

        setIsError(true);
        setIsLoading(false);
        console.log(err);

      }

    }
    getData();
    // eslint-disable-next-line react-hooks/exhaustive-deps

  }, []);

  return (
    <>
      {isLoading ? (
        <h1>Loading ...</h1>
      ) : isError ? (
        <p>Something went wrong</p>
      ) : (
        <Header api={weather} />
      )}
    </>
  );

};
Junius L
  • 15,881
  • 6
  • 52
  • 96