react-weather-app: A Redux Weather Dashboard That Remembers Every Search

A compact open-source project that turns one API call into a growing comparison history, then uses sparklines and a map to make the data easy to scan.

8 min read • View on GitHub • More from zubair-trabzada

An editorial scene of a weather clerk dropping fresh city forecast cards onto the top of a stacked archive. Tiny sparklines peek from the file edges while a wall map shows multiple pinned cities. It explains how the app turns one search into a durable comparison ledger.
The app does not overwrite weather. It appends history.
Key Takeaways

Most weather apps treat a search as a replacement. react-weather-app treats it as a record. Type a city, and the previous result stays on the page while a new one rises to the top. That tiny choice changes the whole product from a forecast view into a living comparison board.

The app's real trick: every search becomes history

The reducer is the headline. Instead of swapping old data out, it prepends each successful response into an array, so the newest city sits at the top and every older search remains available for comparison. That gives the dashboard a memory, which is rare for a utility app and unusually useful for a weather tool.

export default function(state = [], action) {
  switch (action.type) {
    case FETCH_WEATHER:
      return [action.payload.data, ...state];
  }

  return state;
}

One reducer line turns async weather requests into a growing archive.

A close-up of a single forecast card landing on a conveyor that routes it to the front of a stack. Older cards slide backward in order, making the prepend logic visible as a physical mechanism. It explains why the latest city appears first without deleting the past.
Prepend, don't replace.

How one city search travels through the app

The path is clean because the async work is pushed into middleware. The search bar keeps the input controlled locally, then hands the city name to an action creator that returns the axios promise as its payload. redux-promise catches that promise, waits for it to resolve, and dispatches the weather payload to the reducer without extra success or loading actions.

export function fetchWeather(city) {
  const url = `${ROOT_URL}&q=${city},us`;
  const request = axios.get(url);

  return {
    type: FETCH_WEATHER,
    payload: request
  };
}

That is why the action creator stays short. The middleware owns the ceremony, the reducer owns the shape, and the container just moves the city name from a form field into the store.

Why the UI reads fast even though the data is rich

Each row compresses a five-day response into a compact scan line. The three sparklines for temperature, pressure, and humidity do the heavy lifting, while the Google map pins the city in physical space. The result is not a wall of raw weather numbers. It is a comparison interface.

Three city rows laid out like filing strips, each carrying tiny line charts, a location marker, and compact labels. The composition shows how the dashboard turns a dense weather response into something you can compare at a glance. It explains the value of sparklines and a map anchor together.
The rows are small, but the comparisons are loud.

This is the real product choice: the app optimizes for side-by-side judgment. You can compare cities without opening a detail pane or losing the earlier search that got you there.

A time capsule from the class-component era

The repo is also a snapshot of older React habits. Class components, refs, Redux containers, Webpack, Babel stage presets, and a direct Google Maps integration all point to a pre-hooks workflow. That does not make it outdated in a bad sense. It makes it legible. You can see where state lives, where side effects start, and where imperative APIs still need a bridge.

A hand-built bridge connects a neat React house to a heavy industrial map machine. The bridge is made of a ref and a lifecycle method, showing how imperative code can still enter a declarative app. It explains the old-school pattern used to mount Google Maps into React.
React renders the shell. The map still needs a real node.
componentDidMount() {
  this.map = new google.maps.Map(this.refs.map, {
    zoom: 12,
    center: { lat: this.props.lat, lng: this.props.lon }
  });
}

That bridge is the giveaway. React renders the shell, but Google Maps still wants a real DOM node and a lifecycle moment. The old this.refs pattern is blunt by modern standards, yet it makes the integration easy to read. The one thing that does not age well is the hardcoded weather API key. In a production app it should live in an environment variable, not in a checked-in action file.

What this repo teaches better than newer weather apps

The point is not that this repo is the best weather app. It is the clearest explanation of a particular idea: a data model can change a UI from disposable to cumulative. Once you see the prepend-only reducer, the whole dashboard makes sense.

PatternState modelAsync handlingWhat you learn
react-weather-appPrepends each city into a list.redux-promise resolves the axios promise.How one reducer turns search into history.
Typical overwrite-style appReplaces the previous city.One fetch, one result.Basic request flow, little comparison value.
Modern hook-based dashboardLocal or slice state with useEffect and async await.Cleaner ergonomics, less middleware.Modern production patterns, less explicit data flow.
Vanilla localStorage appStores searches in browser storage.Usually direct fetch or await.Lightweight persistence, but less Redux structure.

That is why the repo still matters. It is small enough to understand in one sitting, but specific enough to teach a real architectural idea. The weather data is just the excuse. The lesson is state design.