Building our Weather App One Component at a time

Build the App One Component at a Time

Step 1: App.js — The Main Brain

Open src/App.js and replace its contents with the following:

import React, { useState } from 'react';
import './App.css';
import { getWeatherByCity } from './api/WeatherService';
import SearchBar from './components/SearchBar';
import WeatherCard from './components/WeatherCard';
import TimeDisplay from './components/TimeDisplay';

function App() {
  const [weatherData, setWeatherData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const handleSearch = async (city) => {
    if (!city) return;
    setLoading(true);
    setError('');
    setWeatherData(null);
    try {
      const data = await getWeatherByCity(city);
      setWeatherData(data);
    } catch {
      setError('City not found. Please try another one.');
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="App">
      <h1>React Weather App</h1>
      <TimeDisplay />
      <SearchBar onSearch={handleSearch} />
      {loading && <p>Loading...</p>}
      {error && <p className="error">{error}</p>}
      {weatherData && <WeatherCard data={weatherData} />}
      <footer>
        Made by <a href="https://www.guvi.in" target="_blank" rel="noreferrer">Jaishree Tomar for GUVI</a>
      </footer>
    </div>
  );
}

export default App;

Step 2: WeatherService.js — Talk to the API

Create a file inside src/api/WeatherService.js and paste:

const API_KEY = 'b02928db49861b163d51b3cd51120419';
const BASE_URL = 'https://api.openweathermap.org/data/2.5/weather';

export const getWeatherByCity = async (city) => {
  const response = await fetch(`${BASE_URL}?q=${city}&appid=${API_KEY}&units=metric`);
  if (!response.ok) {
    throw new Error('City not found');
  }
  return await response.json();
};

This fetches data from OpenWeatherMap using a city name.

Don’t forget: Replace the API key if you generate your own at openweathermap.org.

Step 3: SearchBar.js — Let Users Type a City

Inside src/components/SearchBar.js, paste:

import React, { useState } from 'react';

const SearchBar = ({ onSearch }) => {
  const [city, setCity] = useState('');

  const handleKeyPress = (e) => {
    if (e.key === 'Enter') onSearch(city);
  };

  return (
    <div className="search-bar">
      <input
        type="text"
        placeholder="Enter city"
        value={city}
        onChange={(e) => setCity(e.target.value)}
        onKeyPress={handleKeyPress}
      />
      <button onClick={() => onSearch(city)}>Search</button>
    </div>
  );
};

export default SearchBar;

Now the user can type a city and press enter or click the search button.

Step 4: WeatherCard.js — Display Weather

Inside src/components/WeatherCard.js, paste:

import React from 'react';
import './WeatherCard.css';

const WeatherCard = ({ data }) => {
  const { name, main, weather, wind } = data;

  return (
    <div className="weather-card">
      <h2>{name}</h2>
      <img src={`https://openweathermap.org/img/wn/${weather[0].icon}@4x.png`} alt={weather[0].description} />
      <p>{weather[0].main} - {weather[0].description}</p>
      <p>🌡 Temp: {main.temp} °C</p>
      <p>💧 Humidity: {main.humidity}%</p>
      <p>🌬 Wind: {wind.speed} m/s</p>
    </div>
  );
};

export default WeatherCard;

Step 5:

Create a CSS file: src/components/WeatherCard.css

.weather-card {
  background-color: #1c1c1c;
  padding: 2rem;
  margin-top: 2rem;
  border-radius: 12px;
  animation: fadeIn 1s ease-in-out;
}

.weather-card img {
  width: 100px;
  animation: float 2s infinite ease-in-out;
}

@keyframes float {
  0%, 100% {
    transform: translateY(0px);
  }
  50% {
    transform: translateY(-10px);
  }
}

Step 5: TimeDisplay.js — Show Real-Time Clock

Inside src/components/TimeDisplay.js, paste:

import React, { useState, useEffect } from 'react';

const TimeDisplay = () => {
  const [time, setTime] = useState(new Date().toLocaleTimeString());

  useEffect(() => {
    const interval = setInterval(() => {
      setTime(new Date().toLocaleTimeString());
    }, 1000);
    return () => clearInterval(interval);
  }, []);

  return <p className="time-display">Current Time: {time}</p>;
};

export default TimeDisplay;