Creating a weather app with Reactjs - Part 3
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).
4 February 2021 · 4 minute read
Using our data
Alright! Now we have visible data that we can work with. If we go to our DevTools => Network tab, and we look for our fetch calls (one starts with onecall
and the other one with json?latlng
, we can see what the response looks like. That's our data!
For Google Map's Geolocation API, we can see that they give us a lot of information. Which is good, but we don't really need all of that for this app. So, since I only really care about the city's name and the state's "short name" (i.e. California = CA), we can refactor our fetchData
function's final lines like so:
let response = await fetch(APICall);
let data = await response.json();
APIName === "reverseGeocoding" ?
stateFunction(data.results[0].address_components) :
stateFunction(data);
Displaying our data
Great! Now our data is more managable. Now, let's create a simple section that displays current temperature, humidity, wind speed, city name and the state's short name.
return (
<>
{typeof forecast.current != "undefined" && typeof cityInfo[1] != "undefined" ? (
<section>
<h3>Temperature: {forecast.current.temp} °K</h3>
<h3>Humidity: {forecast.current.humidity}%</h3>
<h3>Wind speed: {forecast.current.wind_speed}m/s</h3>
<h3>{cityInfo[1].long_name}, {cityInfo[3].short_name}</h3>
</section>
) : ("")}
</>
)
Awesome! Now we can see the info on the page. We have to add a couple checks before trying to display the info, since it takes a bit for our app to get the data responses. This way, we won't get errors when we first render our app. These checks will also account for the case in which the user denies location access. So, whatever we put in that last part of the tertiary statement will display in case of any errors.
Great, we can see our data, but it's kind of ugly, isn't it? Let's fix that.
Styling using CSS modules
To use CSS modules in React, we'll create a new directory in our /src folder called /styles. Here, we'll have our stylesheets for all our React components (granted, some people prefer to have their css modules in the same directory as the component, but for this case I think this works fine). Let's also create a folder called /components, which we'll populate soon enough.
Before we start using css modules, let's convert our displayed data into it's own component, this will keep our App.js file cleaner and our files easier to handle. So, inside of /components, create a file named "CurrentData.js". Inside our /styles directory, create two css module files: one for App.js, and another for CurrentData.js. The App.module.css file will be our global stylesheet, where we'll reset the margins, define a font for the entire app, define css variables, etc. This is what those files contain.
App.js
return statement
return (
<section className={styles.App}>
{typeof forecast.current != "undefined" && typeof cityInfo[1] != "undefined" ? (
<CurrentData
forecast={forecast}
cityInfo={cityInfo}
/>
) : ("")}
</section>
)
CurrentData.js
, inside the /components
dir
import React from 'react';
import styles from "../styles/CurrentData.module.css";
export default function CurrentData({ forecast, cityInfo }) {
const unixToDate = (unixTimestamp, tzString = "America/Los_Angeles") => {
const miliseconds = unixTimestamp * 1000;
const date = new Date(miliseconds);
return date.toLocaleTimeString("en-GB", { timeZone: tzString });
};
return (
<section className={styles.dataContainer}>
<section className={styles.mainContent}>
<h3>{forecast.current.temp} °K</h3>
<h3>{cityInfo[1].long_name}, {cityInfo[3].short_name}</h3>
</section>
<section className={styles.additionalContent}>
<section className={styles.dataList}
<ul>
<li>Precipitation</li>
<li>Humidity</li>
<li>Wind</li>
</ul>
<ul className={styles.values}>
<li>{forecast.daily[0].pop}%</li>
<li>{forecast.current.humidity}%</li> <li>{parseFloat(forecast.current.wind_speed).toFixed(1)}m/s</li>
</ul>
</section>
<section className={styles.dataList}>
<ul>
<li>Feels like</li>
<li>Sunrise</li>
<li>Sunset</li>
</ul>
<ul className={styles.values}>
<li>{forecast.current.feels_like} °K</li>
<li>{unixToDate(forecast.current.sunrise, forecast.timezone)}</li>
<li>{unixToDate(forecast.current.sunset, forecast.timezone)}</li>
</ul>
</section>
</section>
</section>
);
};
CurrentData.module.css
, inside the /styles
dir
.dataContainer {
grid-column: 2/3;
grid-row: 7/8;
width: 1100px;
height: 500px;
background-color: var(--container-bg-color);
border: var(--container-border);
border-radius: 45px;
padding: 15px;
display: grid;
grid-template-rows: auto 10px auto 10px auto;
}
.mainContent {
grid-row: 1/2;
display: flex;
justify-content: space-evenly;
}
.dataContainer h3 {
font-size: 3rem;
}
.dataContainer ul {
list-style: none;
}
.additionalContent {
grid-row: 3/4;
display: flex;
justify-content: space-evenly;
font-size: 1.5rem;
}
.dataList {
width: 50%;
display: flex;
justify-content: space-around;
}
.values {
color: var(--container-values-color);
}
App.module.css
, inside the /styles
dir
:root {
--body-bg-color: #252525;
--text-color: #fffacd;
--icon-color: #6bb9f0;
--container-bg-color: rgba(0, 0, 0, 0.3);
--container-border: 3px solid #80ffdb;
--container-values-color: #00ced1;
}
* {
margin: 0;
padding: 0;
}
html {
background-color: var(--body-bg-color);
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
color: var(--text-color);
font-size: 16px;
}
.App {
display: grid;
grid-template-columns: 130px auto 130px;
grid-template-rows: 40px auto 20px auto 40px;
}
Our webpage in its current state!
Now we're coding! Don't worry, it looks like a lot but it really isn't. Also, I know the app isn't the most beautifully designed out there, but it serves its teaching purposes.
So, we separated the extense code into the CurrentData component (I called it that because we'll implement daily forecast later). In this component we make use of the data that we retrieved before, and we display it to the user. The unixToDate()
function lets us convert the unix timestamp that we get from the One Call API into readable human time format. And that's it! Our app works! I'll be adding a couple more components over the next posts in the series, but this is the skeleton of it. You've made a weather app that works!