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 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.
Contents
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 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}`
}
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 have almost done, here we have to update our skeleton to get final version of the app. Here on <div> 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>
);
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);
}
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 […]