Creating a weather app with Reactjs - Part 2
Hello! In this series, I'll show you how I went about creating a weather forecast app entirely with Reactjs. The app uses React Hooks, API calls from OpenWeatherMap & Google Geocoding Services, and some CSS modules to make it all responsive (and look nice too, of course).
3 February 2021 · 3 minute read
Fetching and using data.
Now that we have the user's coordinates, we can make a fetch call to the Open Wather Map's One Call API; which we can use to get very useful data, like:
- Current weather
- Hourly forecast for 48 hours
- Daily forecast for 7 days
- And more...
First things first. You'll need to create an account with them, which is free, and generate an API key for the One Call API, which is also free!
Once you do that, you should have an API key that looks something like this: jadi1923mdas012jda...
Should be around 32 characters long. Now we're ready to implement our fetch call!
If we take a look at the One Call API Documentation, we'll see that to make an API call, we use an address like this: https://api.openweathermap.org/data/2.5/onecall?lat={lat}&lon={lon}&exclude={part}&appid={APIKey}
The exclude parameter lets you, well... exclude weather data from the API response. For this app, I don't really care about the minutely or alerts parts of the data, so I'm gonna exclude those like this: "...&exclude=minutely,alerts...".
Since we also want to display the name of the city, we're gonna use Google's Reverse Geocoding API, which takes geographical coordinates, and returns an array of data about those coordinates. To access this API you again need to have a google account and generate an API Key, which is free. This is a process that unfortunately falls out of the scope of this series, but you can learn how to do it here. The reverse geocoding API url looks like this: https://maps.googleapis.com/maps/api/geocode/json?latlng={lat},{long}&key={APIKey}
Once you have both your keys, it's finally time to code!
Important
If you're using git/github, it's important that you dont' put sensitive information out there, like your API Keys. To work around this, put your keys in a separate .js file that you can access from your other files. Then, add this file to .gitignore. This way, no one but you should be able to see your keys.
Since we're gonna need all of this data at initial render, we'll do our fetch calls inside a useEffect() hook. We'll use an additional one to the one we already have, since they do different things. It looks like this:
// Fetching data from different APIs
useEffect(() => {
async function getOneCallData(APIKey, position) {
let lat = position.latitude;
let lon = position.longitude;
const oneCallAPI =
`https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${lon}&exclude=minutely,alerts&appid=${APIKey}`;
let response = await fetch(oneCallAPI);
let data = await response.json();
};
async function getReverseGeocodingData(APIKey, position) {
let lat = position.latitude;
let lon = position.longitude;
const reverseGeocodingAPI =
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lon}&result_type=political&key=${APIKey}`;
let response = await fetch(reverseGeocodingAPI);
let data = await response.json();
};
if (typeof currentLocation.latitude !== "undefined") {
getOneCallData(keys.oneCall, currentLocation);
getReverseGeocodingData(keys.reverseGeocoding, currentLocation);
};
}, [currentLocation]);
As you can see, all we're doing is requesting data from both APIs. To prevent errors, we check first to see if the currentLocation object contains a latitude key. If it does, we'll run our functions. At the end, we tell react to run this hook everytime our currentLocation state updates. If you go to your React page now, and look at the console, you'll see two objects with the data that we requested. Good job!
Since we're using very similar functions both times, we should refactor this into a single function, and save ourselves some space.
// Fetching data from different APIs
useEffect(() => {
async function fetchData(APIKey, APIName, position) {
let lat = position.latitude;
let lon = position.longitude;
let APICall;
switch(APIName) {
case "oneCall":
APICall =
`https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${lon}&exclude=minutely,alerts&appid=${APIKey}`;
break;
case "reverseGeocoding":
APICall =
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lon}&result_type=political&key=${APIKey}`;
break;
};
let response = await fetch(APICall);
let data = await response.json();
};
if (typeof currentLocation.latitude !== "undefined") {
fetchData(keys.oneCall, "oneCall", currentLocation);
fetchData(keys.reverseGeocoding, "reverseGeocoding", currentLocation);
};
}, [currentLocation]);
A bit cleaner, huh?
That data is not useful to us in the console tho, we should store it in state so we can display it. Let's use two new useState() hooks for this.
const [cityInfo, setCityInfo] = useState({});
const [forecast, setForecast] = useState({});
And instead of displaying the data to the console, let's set it to these new state variables inside our fetchData function.
// Fetching data from different APIs
useEffect(() => {
async function fetchData(APIKey, APIName, position, stateFunction) {
...
...
...
stateFunction(data);
};
if (typeof currentLocation.latitude !== "undefined") {
fetchData(keys.oneCall, "oneCall", currentLocation, setForecast);
fetchData(keys.reverseGeocoding, "reverseGeocoding", currentLocation, setCityInfo);
};
}, [currentLocation]);
Done! Our data is now saved in state and we can access it later whenever we need it.