How to Make Weather App in React

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.

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 that we will use for this project. For that, we have to move to the openweather.org site and just log in to get the API key. After that, in our App.js component, we 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 that will differ in certain conditions.

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 added another <div> for location-box and then added <div> for a 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 (
    <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>
  );
Weather App in React

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 added another array for days with all day’s names. Also “d” is here the Date() object which we have passed from the function call. After that we added a variable for the day, here we used days[d.getDay()], getDay() is a function to get the current day.

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}`
  }
Weather App in React

Adding States

After that, we have to add our states, one for query and another for weather. Here query is to make a URL for weather API and weather is for details. Then we have added the 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 the 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 updated the weather and query states.

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);
        });
    }
  }

Updating The Skeleton

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>
  );
Weather App in React

Customizing The Application

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);
}

Full Source Code to Make Calculator in React

index.js

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();

App.js

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;

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);
}

Output

Weather App in React

Check out video reference here:

You may also like:

Reactjs Guru
Reactjs Guru

Welcome to React Guru, your ultimate destination for all things React.js! Whether you're a beginner taking your first steps or an experienced developer seeking advanced insights.

React tips & tutorials delivered to your inbox

Don't miss out on the latest insights, tutorials, and updates from the world of ReactJs! Our newsletter delivers valuable content directly to your inbox, keeping you informed and inspired.

One comment

Leave a Reply

Your email address will not be published. Required fields are marked *

Table of Contents