In this article, we are going to make a weather app in react. In this project, we will use openweather API which provides us free API to get weather details. Here we will add an input field where user will add any city name and as soon city name gets entered an API call will occur and details will be fetched to the screen. This App will be completely depends on API.
So basically this is going to be a beginner-friendly project, so let's make this project step-by-step.
Pre-requisites to Make Calculator in React
- Basic knowledge of ReactJS.
- Basic knowledge of React hooks.
- Good knowledge of React Components.
Adding API And Key
Now before jumping into the code, let's get the API and Key which we will use for this project. For that, we have to move to openweather.org site and just login to get API key. After that, in our App.js component, we have added a constant in which we have assigned our API key to the key constant, and we have provided a URL in our base constant. Also, we have two cool pictures we will differ at some certain condition.
import React, { useState } from 'react';
const api = {
key: "4f8e795dcd6dbf7b9f5276bff095ffc1",
base: "https://api.openweathermap.org/data/2.5/"
}
Creating Skeleton For App
Now let's head to our return statement to create the skeleton for the weather app. Here we have added an input field with a class and placeholder. Then we have added another
for location-box and then added for location with an initial location to check the output. lastly we have added another div where we will add date where we will get date using datebuilder function.`return (
<input
type="text"
className="search-bar"
placeholder="Search..."
/>
</div>
<div>
<div className="location-box">
<div className="location">New York City, US</div>
<div className="date">{dateBuilder(new Date())}</div>
</div>
</div>
</main>
</div>
);`
Creating Date
Now let's get today's date, for that we have added a function named dateBuilder(), here we have added an array for months with all month names. Then we have added another array for days with all days names. Also "d" is here Date() object which we have passed from function call. After that we have added a variable for day, here we have used days[d.getDay()], getDay() is a function to get current day.
Then we have fetched date and similarly month and year, which are return to the function call. Here you can see we have separately made arrays of months and days because getDay() and getMonth() function returns the number of the day and month respectively, so we just need month name and day name not number.
`const dateBuilder = (d) => {
let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
let days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
let day = days[d.getDay()];
let date = d.getDate();
let month = months[d.getMonth()];
let year = d.getFullYear();
return `${day} ${date} ${month} ${year}`
}`
Adding States
After that, we have to added our states, one for query and another for weather. Here query is for to make URL for weather API and weather is for details. Then we have added onChange event on input where we are calling the query, and also we are calling a function named search on onKeyPress event.
function App() {
const [query, setQuery] = useState('');
const [weather, setWeather] = useState({});
return (
<div className=>
<main>
<div className="search-box">
<input
type="text"
className="search-bar"
placeholder="Search..."
onChange={e => setQuery(e.target.value)}
value={query}
onKeyPress={search}
/>
</div>
);}
Calling API to Get Result
Now we have defined search function, in this we have added a condition where if evt.key is equal to Enter. If yes, then we have used fetch() where we have ${api.base}weather?q=${query}&appid=${api.key}&units=metric this line of code to create the API call and this is query syntax for URL, and we used then(res => res.json()) to get results in JSON format. After that we have updated weather and query states.
const search = evt => {
${api.base}weather?q=${query}&appid=${api.key}&units=metric
if (evt.key === "Enter") {
fetch()
.then(res => res.json())
.then(result => {
setWeather(result);
setQuery('');
console.log(result);
});
}
}
Updating The Skeleton
Now we have almost done, here we have to update our skeleton to get final version of the app. Here on
with a condition to check weather.main is not equal undefined, if yes then we will add app warm class otherwise app class. These classes are having some CSS to change background picture and style.Then we have again checked a condition to check weather is not undefined, then we will display location box and weather box. At location, we have dynamically assigned the location and country. Then in the weather box, we have assigned the temperature and weather name.
return (
<div className={(typeof weather.main != "undefined") ? ((weather.main.temp > 16) ? 'app warm' : 'app') : 'app'}>
<main>
<div className="search-box">
<input
type="text"
className="search-bar"
placeholder="Search..."
onChange={e => setQuery(e.target.value)}
value={query}
onKeyPress={search}
/>
</div>
{(typeof weather.main != "undefined") ? (
<div>
<div className="location-box">
<div className="location">{weather.name}, {weather.sys.country}</div>
<div className="date">{dateBuilder(new Date())}</div>
</div>
<div className="weather-box">
<div className="temp">
{Math.round(weather.main.temp)}°c
</div>
<div className="weather">{weather.weather[0].main}</div>
</div>
</div>
) : ('')}
</main>
</div>
);
Customizing The Application
Now our structure is pretty good, and we have added almost everything but before going to next move, let's add some colors and customize this calculator, so this can looks like calculator atleast. I won't go deep in CSS because CSS is actually depended on you and this is not that much hard to put color or something. So if you want same CSS then use below CSS.
index.css
`*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Montserrat', sans-serif;
}
.app {
background-image: url('./assets/cold-bg.jpg');
background-size: cover;
background-position: bottom;
transition: 0.4 ease;
}
.app.warm {
background-image: url('./assets/warm-bg.jpg');
}
main {
min-height: 100vh;
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.75));
padding: 25px;
}
.search-box {
width: 100%;
margin: 0 0 75px;
}
.search-box .search-bar {
display: block;
width: 100%;
padding: 15px;
appearance: none;
background: none;
border: none;
outline: none;
background-color: rgba(255, 255, 255, 0.5);
border-radius: 0px 0px 16px 16px;
margin-top: -25px;
box-shadow: 0px 5px rgba(0, 0, 0, 0.2);
color: #313131;
font-size: 20px;
transition: 0.4s ease;
}
.search-box .search-bar:focus {
background-color: rgba(255, 255, 255, 0.75);
}
.location-box .location {
color: #FFF;
font-size: 32px;
font-weight: 500;
text-align: center;
text-shadow: 3px 3px rgba(50, 50, 70, 0.5);
}
.location-box .date {
color: #FFF;
font-size: 20px;
font-weight: 300;
font-style: italic;
text-align: center;
text-shadow: 2px 2px rgba(50, 50, 70, 0.5);
}
.weather-box {
text-align: center;
}
.weather-box .temp {
position: relative;
display: inline-block;
margin: 30px auto;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 16px;
padding: 15px 25px;
color: #FFF;
font-size: 102px;
font-weight: 900;
text-shadow: 3px 6px rgba(50, 50, 70, 0.5);
text-align: center;
box-shadow: 3px 6px rgba(0, 0, 0, 0.2);
}
.weather-box .weather {
color: #FFF;
font-size: 48px;
font-weight: 700;
text-shadow: 3px 3px rgba(50, 50, 70, 0.5);
}
`
Read More
Top comments (0)