[Guide] Build a Weather App (Cache Bypass Default) - implementation notes
The Weather App guide is a clean example of treating freshness as a route contract: cache bypass by default, visible lane markers, and stored derived summaries (now bundle, hourly strip, daily cards, alerts) so switching panels/locations is instant even while data is streaming in. I'm curious how people balance "always fresh" posture with UI stability and debuggability.
Did you keep cacheLane=bypass as the default, or did you introduce caching for specific panels/locations? How far did you go with stored derived outputs (cards/strips/feels-like bundles) before it became hard to keep derivations correct? What evidence do you render so a screenshot can explain *which* location/panel/lane the user is in? If you have favorites and duplicate reads (list + detail), what is your merge rule when the reads disagree?
Comments (16)
Back to latestBypass-by-default made the app feel honest.
But we still had to make the lane visible or it just felt like the UI was randomly changing.
Storing derived cards was worth it because multiple panels read the same shape.
We had one helper that writes cards[locationId] and a lastDerivedAtByLocation evidence timestamp.
Counterpoint: bypass-by-default can create churn if your API updates frequently.
We used route posture to switch to cache for hourly when the user is just browsing historical-ish data.
Same. The guide's key idea is that posture is explicit, not that bypass is morally correct.
If you choose cache for a panel, render data-cache-lane=cache and it's still debuggable.
We rendered evidence on the shell: data-location, data-panel, data-cache-lane, data-render-cadence.
It made screenshots actionable immediately.
A small derive helper for the "feels like" bundle kept our UI consistent:
ts
function deriveFeelsLike(now: any) {
return { tempC: now.tempC, windKph: now.windKph, feelsLikeC: now.tempC - 1 };
}
Even if the math is fake, having a stable derived shape matters for coherence.
Favorites in a vault were nice because it made the list route and detail route agree.
If favorites live in component state, the app feels inconsistent across navigation.
Merge rule for duplicate reads: we store forecastRevision per location and only apply newer reads.
Without it, you get that annoying flip where the UI seems to go backward.
A misunderstanding I had: I assumed "stored derived" was a performance trick.
In this guide it's more about stable UI contracts and debuggability than speed.
Docs tie-in: this is basically the data fetching posture + a route contract story for freshness.
Related: Data Fetching and Caching (Best Practices) and Performance and Rendering (Best Practices).
We kept panel in global route state (now|hourly|daily) and it made the app feel coherent.
Without it, you end up with panels that don't match the URL and back/forward becomes weird.
Counterpoint: storing hourly strips can get large and make memory usage weird on long sessions.
We stored a derived summary strip (coarser) and kept the raw list only in the forecast payload.
That seems right. Derived state should be the render-ready shape, not a second copy of raw data.
If it's too big, your derived shape isn't a summary anymore.
We also rendered a data-freshness-at timestamp to avoid arguments about whether the UI updated.
It's a tiny piece of evidence that saves a lot of time.
We let cache lane switch based on battery saver mode (warm cadence, cache lane cache).
Explicit posture made it feel like a feature rather than a bug.
If you store derived summaries, centralize writes or you'll forget to re-derive on some mutation path.
We treat derive as mandatory after any forecast write.
We used the same evidence posture for alerts: store a derived alertSummary string and render it in the header.
Users care more about the summary than the raw payload.
The guide is a good reminder that "fresh" isn't a vibe. It's a posture you can encode and render.