1

I have this react component which every time it's rendered show the country information that receives via props (country) and using the weather stack API must show also the capital weather at the current time. The first part (displaying the country data that comes from the props) works fine but I'm struggling to get the data from the weather API. I see on console that I'm getting the current weather but can't assign it to weather variable using setState() therefore my app crashes.

This is the component code I have so far, I've tried using async/await and .then synataxis in case I was mispelling something but always I get the same result:

const CountryDetails = async ({country}) => {
    
    const [weather, setWeather] = useState({});

    // const hook = async () => {
    //   const result = await axios.get(`http://api.weatherstack.com/current?access_key=${WEATHER_API}&query=${country.capital}`);
    //   console.log(result.data);
    //   setWeather(result.data.current);
    //   console.log(weather);
    // }

    const hook = () => {
      axios.get(`http://api.weatherstack.com/current?access_key=${WEATHER_API}&query=${country.capital}`).then((response) => {
        console.log('then');
        setWeather({
          temperature: response.data.current.temperature,
          img: response.data.current.weather_icons,
          wind: response.data.current.wind_speed,
          dir: response.data.current.wind_direction
        });
        console.log(response.data.current);
      });
    }

    useEffect(hook, []);

    console.log(weather);

    return (
      <>
        <h1>{country.name}</h1>
        <p>capital {country.capital}</p>
        <p>population {country.population}</p>
        <h2>languages</h2>
        <ul>
          {country.languages.map((lang) => {
            <li key={lang.name}>{lang.name}</li>;
          })}
        </ul>
        <img src={country.flag}></img>
        <h2>Weather in {country.capital}</h2>
        <p><b>temperature: </b>{weather.current.temperature}</p>
        <img src={weather.current.weather_icons} />
        <p><b>wind: </b>{weather.current.wind_speed} direction {weather.current.wind_direction}</p>
      </>
    );
  };

sandbox with the whole code: https://codesandbox.io/s/vigilant-ride-h3t1j

3
  • Why do you have async in your component's function definition? Would just removing it work? Commented Feb 8, 2021 at 10:56
  • firstly I was using async/await syntax now I've removed but still don't work Commented Feb 8, 2021 at 10:59
  • you initialize weather with an empty object and try to access its properties in your jsx. the line <p><b>temperature: </b>{weather.current.temperature}</p> will fail when your component is rendered Commented Feb 8, 2021 at 11:08

2 Answers 2

1

Here is a codesandbox I created playing around with your code. Since you stated that you're receiving the data from the API successfully, I'm mocking that with my getWeather function. In addition to what @Viet answered, there were other issues in the code you provided. See if this helps or if the error still persists, please provide with a reproduced example of the snippet:

https://codesandbox.io/s/competent-dhawan-fds81?file=/src/App.js:52-62

import { useEffect, useState } from "react";

const getWeather = (country) => {
  return Promise.resolve({
    data: {
      current: {
        temperature: "<temperature>",
        weather_icons: "<weather_icons>",
        wind_speed: "<wind_speed>",
        dir: "<wind_direction>"
      }
    }
  });
};

const CountryDetails = ({ country }) => {
  const [weather, setWeather] = useState({});

  const hook = () => {
    getWeather(country).then((response) => {
      console.log("then");
      setWeather({
        temperature: response.data.current.temperature,
        img: response.data.current.weather_icons,
        wind: response.data.current.wind_speed,
        dir: response.data.current.dir,
        wind_speed: response.data.current.wind_speed
      });
      console.log(response.data.current);
    });
  };

  useEffect(hook, [country]);

  // You should get {} logged here, not undefined
  console.log(weather);

  return (
    <>
      <h1>{country.name}</h1>
      <p>Capital: {country.capital}</p>
      <p>Population: {country.population}</p>
      <h2>Languages</h2>
      <ul>
        {/* You were not returning anything in the callback of the map function */}
        {country.languages.map((lang, i) => (
          <li key={i}>{lang.name}</li>
        ))}
      </ul>
      <img src={country.flag}></img>
      <h2>Weather in {country.capital}</h2>
      <p>
        <b>temperature: </b>
        {/* As @Veit mentioned, you were accessing the wrong property */}
        {weather.temperature}
      </p>
      <img src={weather.weather_icons} />
      <p>
        <b>Wind: </b>
        {weather.wind_speed} Direction: {weather.dir}
      </p>
    </>
  );
};

export default (props) => {
  const country = {
    languages: [{ name: "<name>" }],
    flag: "<flag name>",
    capital: "<capital name>",
    name: "<Coutry Name>",
    population: "<POPULATION>"
  };
  return <CountryDetails country={country} />;
};

Sign up to request clarification or add additional context in comments.

8 Comments

I'm getting the same result :(
this is a sandbox with all my code codesandbox.io/s/vigilant-ride-h3t1j maybe the problem came from other side
Can you please check. This sandbox is empty, no new code than the codesandbox's boilerplate.
check now on the index.js file seems like I didn't saved it
if you type on the search inbox swe and click on the button next to sweden you should see the country'details and curentweather
|
0

You are just extracting wrong properties from weather state. This works:

import axios from "axios";
import { useState, useEffect } from "react";

const WEATHER_API = "xxx";

const CountryDetails = ({ country }) => {
  const [weather, setWeather] = useState({});
 
  const hook = () => {
    axios
      .get(
        `http://api.weatherstack.com/current?access_key=${WEATHER_API}&query=${country.capital}`
      )
      .then((response) => {
        console.log("then", response);
        setWeather({
          temperature: response.data.current.temperature,
          img: response.data.current.weather_icons,
          wind: response.data.current.wind_speed,
          dir: response.data.current.wind_dir
        });
        console.log(JSON.stringify(weather));
      });
  };

  useEffect(hook, []);

  console.log(weather);

  return (
    <>
      <h2>languages</h2>
      <p><b>temperature: </b>{weather.temperature}</p>
      <p>
        <b>wind: </b>
        {weather.wind} direction {weather.dir}
      </p>
    </>
  );
};

export default function App() {
  return (
    <div className="App">
      <CountryDetails country={{ capital: "London" }} />
    </div>
  );
}

11 Comments

I just tryed like you did but still gettin the same error and on the line where it says console.log(weather) stills returning undefined it's like the setWeather it's not working
hm, then you should check the API key and country,capital. What was the response from axios.get()?
What I used: <CountryDetails country={{ capital: "London" }} />
I did and it's working fine, actually on the console.log(reponse) inside the .then I see the result and it's correct
Yes but if I'm pass a country object should not work equally? also I need the country information nit just the capital
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.