Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
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 the 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 completely depend on API.
So basically this is going to be a beginner-friendly project, so let’s make this project step-by-step.
import React, { useState } from 'react';
const api = {
key: "4f8e795dcd6dbf7b9f5276bff095ffc1",
base: "https://api.openweathermap.org/data/2.5/"
}
return (
<div className="app">
<main>
<div className="search-box">
<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>
);
Then we have fetched the date and similarly month and year, which are returned to the function call. Here you can see we have separately made arrays of months and days because the getDay() and getMonth() function returns the number of the day and month respectively, so we just need the month name and day name not the 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}`
}
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>
);}
const search = evt => {
if (evt.key === "Enter") {
fetch(`${api.base}weather?q=${query}&appid=${api.key}&units=metric`)
.then(res => res.json())
.then(result => {
setWeather(result);
setQuery('');
console.log(result);
});
}
}
Now we are almost done, here we have to update our skeleton to get the final version of the app. Here on <div> with a condition to check the weather.main is not equal undefined, if yes then we will add app warm class otherwise app class. These classes have some CSS to change the background picture and style.
Then we have again checked a condition to check the weather is not undefined, and then we will display the 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>
);
Now our structure is pretty good, and we have added almost everything but before going to the next move, let’s add some colors and customize this calculator, so this can look like a calculator at least. I won’t go deep in CSS because CSS is actually dependent on you and this is not that hard to put color or something. So if you want the same CSS then use the 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);
}
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
import React, { useState } from 'react';
const api = {
key: "4f8e795dcd6dbf7b9f5276bff095ffc1",
base: "https://api.openweathermap.org/data/2.5/"
}
function App() {
const [query, setQuery] = useState('');
const [weather, setWeather] = useState({});
const search = evt => {
if (evt.key === "Enter") {
fetch(`${api.base}weather?q=${query}&appid=${api.key}&units=metric`)
.then(res => res.json())
.then(result => {
setWeather(result);
setQuery('');
console.log(result);
});
}
}
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}`
}
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>
);
}
export default App;
* {
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);
}
[…] Posted on Nov 6 • Originally published at reactjsguru.com […]