Skip to content

About

Weather finder built with React 19, TypeScript and CSS Modules. Fetches OpenWeatherMap data with Axios and validates it with Valibot. Project 08 of the Udemy course "React de Principiante a Experto".

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Weather Finder – React, TypeScript and CSS Modules

A weather finder built with React 19 and TypeScript. You type a city and pick a country, and the app shows the current temperature with the day's minimum and maximum, using data from the OpenWeatherMap API.

This is Project 08 of the Udemy course React de Principiante a Experto. The goal of this project is to consume an external API with Axios, validate its response at runtime with Valibot, keep the fetching logic in a custom hook, and style components with CSS Modules.

The search form filled with Madrid and Spain on the left, and a white card on the right showing 33 °C with a minimum of 31 °C and a maximum of 34 °C

Features

  • Search the current weather by city and country.
  • Both fields are required. An alert shows up if one is empty.
  • The temperature is shown in Celsius, with the minimum and maximum.
  • A spinner is shown while the request is in progress.
  • A "Ciudad No Encontrada" message is shown when the city does not exist.
  • Two-column layout on wide screens, one column on mobile.

Tech Stack

How It Works

All the fetching logic lives in the useWeather custom hook. App only reads its state and passes fetchWeather down to the form.

Form ──fetchWeather({ city, country })──▶ useWeather
                                            │
                                            ├─ 1. Geocoding API  →  city, country  ▶  lat, lon
                                            │     (no result → notFound = true)
                                            ├─ 2. Weather API    →  lat, lon       ▶  raw JSON
                                            └─ 3. Valibot parse(WeatherSchema)     ▶  typed Weather
                                                                                       │
App ◀── weather, loading, notFound, hasWeatherData ─────────────────────────────────────┘
 ├── loading        → <Spinner />
 ├── hasWeatherData → <WeatherDetail />
 └── notFound       → <Alert>

The API returns temperatures in Kelvin. The formatTemperature helper converts them to Celsius before they are shown.

Project Structure

src/
├── components/
│   ├── Alert/            # Message for validation errors and "city not found"
│   ├── Form/             # City input and country select
│   ├── spinner/          # Loading spinner (plain CSS)
│   └── WeatherDetail/    # Card with the current, min and max temperature
├── data/
│   └── countries.ts      # Countries available in the select
├── helpers/
│   └── index.ts          # Kelvin to Celsius conversion
├── hooks/
│   └── useWeather.ts     # API calls, Valibot schema and weather state
├── types/
│   └── index.ts          # SearchType and Country types
├── App.tsx               # Layout and conditional rendering
├── index.css             # Global styles and CSS variables
└── main.tsx

Each component keeps its styles next to it in a *.module.css file.

What I Learned

  • Consuming an external API with Axios. Two chained requests: the Geocoding API turns a city name into coordinates, and the Weather API uses them to get the current weather.
  • Environment variables in Vite. The API key is read from import.meta.env.VITE_API_KEY, and only variables with the VITE_ prefix reach the client code.
  • Validating API responses at runtime. TypeScript types disappear at runtime, so an external response cannot be trusted just because it is typed. A Valibot schema checks the shape of the response, and InferOutput derives the Weather type from that same schema.
  • Custom hooks. useWeather holds the state and the fetching logic, so the components only render what it returns.
  • Handling loading and error states. loading shows the spinner, notFound shows the alert, and finally makes sure the spinner is hidden whatever happens.
  • CSS Modules. Class names are scoped to each component, so two components can use .container without clashing.
  • Typing events and props. ChangeEvent for inputs and selects, SubmitEvent for the form, and ReactNode for components that receive children.

Getting Started

Requirements: Node.js 20 or later and a free OpenWeatherMap API key.

# Clone the repository
git clone https://github.com/TarekM-7/clima-react-typescript.git
cd clima-react-typescript

# Install dependencies
npm install

# Add your API key
cp .env.example .env
# then set VITE_API_KEY in .env

# Start the dev server
npm run dev

Other scripts:

npm run build     # Type-check and build for production
npm run preview   # Preview the production build
npm run lint      # Run ESLint

Note: every VITE_ variable ends up in the browser bundle, so the API key is visible to anyone using the deployed app. That is acceptable for a free key in a learning project. A real app would call the API from a backend.

Acknowledgements

Project idea and design come from the Udemy course linked above. I wrote the implementation while following the course and adapted it as I learned.

About

Weather finder built with React 19, TypeScript and CSS Modules. Fetches OpenWeatherMap data with Axios and validates it with Valibot. Project 08 of the Udemy course "React de Principiante a Experto".

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages