Home > front end >  Fetching weather data from Foreca weather API in react
Fetching weather data from Foreca weather API in react

Time:12-09

I'm trying to fetch weather data from Foreca Weather api (https://rapidapi.com/foreca-ltd-foreca-ltd-default/api/foreca-weather/). To fetch current weather, location parameter is required which is a string of numbers different for different cities. This location parameter can be fetched from their location search endpoint.

I have a function searchCity which fetches location id and then passes it to the weatherUrl to fetch the current weather. The first time I search for a city I do get the locations array, but not the current weather and axios throws 400 bad request error. The second time I search it gives me both, but the current weather response is from the last api call.

Here's the code.
import React from 'react'
import { useState } from 'react';
import axios from 'axios';
const Home = () => {
  // const [weather, setWeather] = useState({});
  const [city, setCity] = useState('');
  const [location, setLocation] = useState([""]);
  const [weather, setWeather] = useState({});


  const url = `https://foreca-weather.p.rapidapi.com/location/search/${city}`
  let weatherUrl;
  const options = {
    headers: {
      'X-RapidAPI-Key': 'apiKeyHere',
      'X-RapidAPI-Host': 'foreca-weather.p.rapidapi.com'
    }
  };
  const weatherOptions = {
    params: { alt: '0', tempunit: 'C', windunit: 'MS', tz: 'Europe/London', lang: 'en' },
    headers: {
      'X-RapidAPI-Key': 'apiKeyHere',
      'X-RapidAPI-Host': 'foreca-weather.p.rapidapi.com'
    }
  };

  const searchCity = async (e) => {
    try {
      if (e.key === 'Enter') {
        await axios.get(url, options).then((response) => {
          setLocation(response.data.locations);
          console.log(response.data);
          weatherUrl = `https://foreca-weather.p.rapidapi.com/current/${location[0]?.id}`;
        })
        setCity('')

// To show the current weather of the city searched

        currentWeather(); 


      }
    } catch (err) {
      console.error(err);
    }
  }

  const currentWeather = async () => {
    try {
      await axios.get(weatherUrl, weatherOptions).then((response) => {
        setWeather(response.data);
        console.log(response.data);
      })
    } catch (err) {
      console.error(err);
    }

  }
  return (
    <> <div>
        <div className="search">
          <input
            value={city}
            onChange={e => setCity(e.target.value)}
            onKeyPress={searchCity}
            type="text" />
        </div>

        <div className="weather">
          <h1>City:{location[0]?.name}</h1>
          <h1>Country:{location[0]?.country}</h1>
          <h1>id:{location[0]?.id}</h1>
          <h1>weather:{weather.current?.temperature}</h1>
        </div>
      </div>
    </>

  )
}

export default Home;


What am I doing wrong or are there better ways to achieve this?

CodePudding user response:

When setting the new state from the response of the locations request, you try to immediately access the state. This is not possible since the state is not immediately updated. Which explains the problem with getting the result from the previous city.

await axios.get(url, options).then((response) => {
  setLocation(response.data.locations);
  console.log(response.data);
  // weatherUrl = `https://foreca-weather.p.rapidapi.com/current/${location[0]?.id}`;
});

To avoid this you could do the same as you did with the url

const url = `https://foreca-weather.p.rapidapi.com/location/search/${city}`;

const weatherUrl = `https://foreca-weather.p.rapidapi.com/current/${location[0]?.id}`;

CodePudding user response:

Removed axios and just used fetch instead and now it works fine.

import React from 'react'
import { useState } from 'react';
const Home = () => {
  const [city, setCity] = useState('');
  const [location, setLocation] = useState([]);
  const [weather, setWeather] = useState({});
  const url = `https://foreca-weather.p.rapidapi.com/location/search/${city}`
  const options = {
    headers: {
      'X-RapidAPI-Key': 'apiKeyHere',
      'X-RapidAPI-Host': 'foreca-weather.p.rapidapi.com'
    }
  };
  const weatherOptions = {
    params: { alt: '0', tempunit: 'C', windunit: 'MS', tz: 'Europe/London', lang: 'en' },
    method: 'GET',
    headers: {
      'X-RapidAPI-Key': 'apiKeyHere',
      'X-RapidAPI-Host': 'foreca-weather.p.rapidapi.com'
    }
  };


  let weatherUrl;

  const searchCity = async (e) => {
    try {
      if (e.key === 'Enter') {
        fetch(url, options)
          .then(response => response.json())
          .then(response => {
            setLocation(response.locations)
            weatherUrl = `https://foreca-weather.p.rapidapi.com/current/${response.locations[0]?.id}`;
            currentWeather();
          })
      }
    } catch (err) {
      console.error(err);
    }
  }

  const currentWeather = async () => {
    try {
      fetch(weatherUrl, weatherOptions)
        .then((response) => response.json())
        .then(response => {
          setWeather(response.current);
          console.log(response.current);
        })
    }
    catch (err) {
      console.error(err);
    }
  }

  return (
    <> <div>
      <div className="search">
        <input
          value={city}
          onChange={e => setCity(e.target.value)}
          onKeyPress={searchCity}
          type="text" />
      </div>

      <div className="weather">
        <h1>City:{location[0]?.name}</h1>
        <h1>Country:{location[0]?.country}</h1>
        <h1>id:{location[0]?.id}</h1>
        <h1>weather:{weather.temperature}</h1>
      </div>
    </div>
    </>
  )
}

export default Home
  • Related