Building a Production React Data Layer: Caching, Deduplication, Retries, and Optimistic Updates

Most React apps do not fail in production because of a missing feature. They fail because of the quiet stuff: the same endpoint called six times on page load, a flaky mobile connection that turns one failed request into a blank screen, a "like" button that waits 800 ms before anything happens, or a retry loop that hammers an API that is already struggling.

Those problems share one root cause. The app treats server data like local state. It is not. Server data is remote, shared, asynchronous, and potentially out of date the instant you receive it. A production-grade data layer is the part of your front end that admits this and handles it deliberately.

This guide shows how to build that layer step by step with React 19 and TanStack Query v5: a typed fetch client, a cache strategy with explicit freshness rules, request deduplication, a retry policy that does not make outages worse, and optimistic updates with safe rollback. Every pattern includes code you can adapt, plus the failure modes that tend to show up only after launch.

Who this is for: developers who already know React hooks and want a repeatable architecture for server state instead of scattered useEffect fetches.

What you will build:

  • A fetch wrapper with typed errors, timeouts, and cancellation
  • A query key factory and cache policy per data class