I am trying to create a WeatherApp using React and OpenWeathermap API as beginner project. After fetching the data from the API, I am not able to return any component as it always returns null from the conditional statement.
import React, {useEffect, useState } from "react";
export default function App(){
const API_KEY = somekey;
const [lat, setLat] = useState([]);
const [long, setLong] = useState([]);
const [data, setData] = useState([]);
useEffect(() => {
const fetchData = async () => {
navigator.geolocation.getCurrentPosition(function (position) {
console.log(position.coords.latitude);
setLat([position.coords.latitude]); //sets latitude
setLong([position.coords.longitude]); //sets longitude
});
await fetch(
`https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${long}&exclude=hourly,minutely&units=metric&appid=${API_KEY}`
)
.then((res) => res.json())
.then((result) => {
setData([result]);
console.log(data);
});
};
fetchData();
}, [lat, long]);
return (
<div className="App">
{(typeof data.main !== 'undefined') ? (
<h1>{data.name}</h1> //doesnt execute
) :null}
</div>
);
}
The project is based on this example:https://www.freecodecamp.org/news/learn-react-by-building-a-weather-app/
since navigator.geolocation.getCurrentPosition is asynchronous you call fetch before setLat etc is called
Note: my knowledge of reactjs is limited, so perhaps you can't do the following in useEffect - apologies in advance if that's the case
In fetchData you would get the data from openweathermap in the callback in navigator.geolocation.getCurrentPosition - like so
const fetchData = () => {
navigator.geolocation.getCurrentPosition(position => {
setLat([position.coords.latitude]); //sets latitude
setLong([position.coords.longitude]); //sets longitude
fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${position.coords.latitude}&lon=${position.coords.longitude}&exclude=hourly,minutely&units=metric&appid=${API_KEY}`)
.then(res => res.json())
.then(result => {
setData([result]);
});
});
};
Note, not using any async since there's no use of await
If you want to use async await, you could "promisify" navigator.geolocation.getCurrentPosition like so
const getCurrentPosition = options => new Promise((resolve, reject) => navigator.geolocation.getCurrentPosition(resolve, reject, options));
then you can use it like so
const fetchData = async () => {
const position = await getCurrentPosition(); // the promisified function above
setLat([position.coords.latitude]); //sets latitude
setLong([position.coords.longitude]); //sets longitude
const res = await fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${position.coords.latitude}&lon=${position.coords.longitude}&exclude=hourly,minutely&units=metric&appid=${API_KEY}`);
const result = await res.json();
setData([result]);
};
Note also, that in both cases, the code uses position.coords.latitude and position.coords.longitude in the call to openweathermap rather than lat and long - because of my lack of knowledge regarding reactjs, I don't know if setLat for instance, changes lat "synchronously" or not (again, my reactjs knowledge is very limited)