Project 2

Project 2
Weather App
Search a city, fetch real data, and handle loading and error states properly
Difficulty: Beginner / Intermediate Builds on: Fundamentals Ch 1–8

Project 1 worked entirely with local state — nothing ever left the browser. This project introduces a real external dependency: a weather API. That single change brings a whole new category of things to handle correctly — the data isn't there immediately, the request can fail, and the UI needs to make sense in all three states (loading, error, and loaded), not just the happy path.

Skills This Project Exercises
useEffect / fetch Loading & error state Controlled search input Conditional rendering async/await
A free, no-API-key weather source
Open-Meteo provides a free weather API that doesn't require signing up for an API key, which makes it a good fit for a learning project. It needs latitude/longitude rather than a city name directly — Open-Meteo's own free geocoding endpoint converts a typed city name into coordinates first, so the app actually makes two fetches per search: one to resolve the city name, one to get the weather for those coordinates.

Requirements

  • A text input where the user types a city name, with a search button (or Enter-to-search).
  • While a search is in progress, show a clear loading indicator instead of stale or blank content.
  • If the city can't be found, or the request fails, show a readable error message — not a blank screen or a crash.
  • On success, display at minimum: the city name, current temperature, and a short description (e.g. "Clear sky," "Light rain").
  • Searching for a new city should correctly replace the previously shown result, not append to it.
  • An empty search input should not trigger a request at all.

Suggested Component Breakdown

App └── WeatherApp // holds city, weatherData, status state (idle/loading/error/success) ├── SearchForm // controlled input + search button └── WeatherDisplay // reads status and renders the matching UI for each case

The status state is the important design decision here — rather than separate isLoading/hasError booleans that could theoretically contradict each other, a single status value ("idle" | "loading" | "error" | "success") guarantees the UI is always in exactly one well-defined state, using the lookup-object/conditional patterns from Fundamentals Chapter 5.

A Reasonable Build Order

  1. Build SearchForm first with just a controlled input and a submit handler that logs the typed city name — no fetching yet.
  2. Manually call the geocoding endpoint once in the browser/Postman/curl for a known city, to see the actual JSON shape you'll be working with before writing any fetch code.
  3. Wire up the geocoding fetch inside an async function triggered on form submit, storing the resolved coordinates in state.
  4. Add the second fetch for the actual weather data once coordinates are available, setting status to "loading" before it starts and "success" once it resolves.
  5. Wrap both fetches in a try/catch, setting status to "error" (with a stored error message) if either one fails.
  6. Build out WeatherDisplay last, rendering different JSX for each of the four status values.
Stretch Goals
  • Show a multi-day forecast, not just current conditions.
  • Add a Celsius/Fahrenheit toggle.
  • Use the browser's Geolocation API to default to the user's current location on first load.
  • Cache recent searches so re-searching the same city doesn't re-fetch immediately.
  • Add simple weather-appropriate icons or background colors based on the description returned.
This project has no single solution file — the requirements above and your own judgment are the spec. Compare notes against the suggested component breakdown once you have something working, not before.