React Query

Learn how React Query manages server state through caching, invalidation, retries, background refresh, and mutation workflows.

Last reviewed: June 2026

·React 16+React 18TanStack Query 5.x
✅
Quick Understanding: React Query is for server state, not general UI state. It solves fetching, caching, refetching, and mutation coordination so components stop reimplementing loading and cache logic manually.

🔍 What Is It?

React Query manages asynchronous server state.

  • →Query keys identify cached resources
  • →Queries fetch and cache remote data
  • →Mutations change remote data and trigger invalidation or optimistic updates
  • →Freshness and retry behavior are configurable from business needs

🎯 Why Do We Need It?

Manual fetching inside useEffect creates repeated boilerplate, duplicated network calls, race conditions, and inconsistent cache behavior. React Query gives teams one place to reason about freshness and mutation flow.

🏗️ What Happens in Real Projects?

Teams use React Query in dashboards, admin apps, and SaaS products where many screens reuse the same remote entities and need reliable background refresh, retry, pagination, and mutation handling.

⚙️ How It Works

A query hook runs with a query key and fetch function. React Query caches the result, deduplicates requests, and decides when to reuse, refetch, or invalidate that data. Mutations can optimistically update UI and then reconcile with the server response.

💻 Example

Query and Mutation Discipline — Stable query keys and clear invalidation keep server state trustworthy.

tsx
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';

function useInvoices(accountId: string) {
  return useQuery({
    queryKey: ['invoices', accountId],
    queryFn: () => fetch(`/api/accounts/${accountId}/invoices`).then((r) => r.json()),
    staleTime: 60_000,
  });
}

function InvoiceList({ accountId }: { accountId: string }) {
  const queryClient = useQueryClient();
  const invoices = useInvoices(accountId);

  const markPaid = useMutation({
    mutationFn: (invoiceId: string) =>
      fetch(`/api/invoices/${invoiceId}/pay`, { method: 'POST' }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['invoices', accountId] });
    },
  });

  if (invoices.isLoading) return <p>Loading...</p>;
  if (invoices.isError) return <p>Failed to load invoices.</p>;

  return (
    <ul>
      {invoices.data.map((invoice: Invoice) => (
        <li key={invoice.id}>
          {invoice.number}
          <button onClick={() => markPaid.mutate(invoice.id)}>Mark paid</button>
        </li>
      ))}
    </ul>
  );
}

🤔 Common Confusions

❓ Should React Query replace Redux or Zustand?

No. React Query is primarily for server state. Redux and Zustand are general client-state tools. Many apps use React Query plus a small local state tool together.

❓ What makes a good query key?

A stable key that uniquely identifies the remote resource and all relevant parameters. Weak query keys are a common source of stale or mixed data.

🚨 Common Production Issues

Weak query keys cause cache collisions and confusing stale data.

Over-invalidation creates unnecessary refetch storms after mutations.

Teams keep staleTime at the default everywhere instead of matching business freshness needs.

✅ Best Practices

Treat query keys as part of the app contract.

Choose staleTime from user expectations and API cost, not habit.

Handle mutations with deliberate invalidation or optimistic updates.

Keep client UI state outside React Query unless it directly represents remote data lifecycle.

🏛️ Architect's Note

Senior Architect's Perspective

React Query changes architecture because it makes server state first-class instead of pretending remote data is just another local state value. Teams that adopt it well usually reduce effect boilerplate and clarify cache ownership significantly.

💬 Frequently Asked Questions

When would I choose RTK Query instead?

Usually when the app is already committed to Redux and the team wants one integrated event, cache, and tooling story instead of separate state layers.

🎯 Key Takeaways

1React Query is for server state, not general UI state.
2Stable query keys are critical for correct caching.
3Invalidation and freshness should reflect product needs.
4It removes a lot of manual fetching boilerplate from components.

🎯 Practice this topic in interviews

↗ Where this topic fits

Sources

Sources / References

Use these React references to verify the concept in official docs and continue into the most relevant SplashRide pages.

Related SplashRide pages

SplashRide React learning path

Browse the full React topic collection and learning order on SplashRide.

React Interview Prep

Practice React interview questions and scenario-based answers.

Frontend Engineer Career Path

A beginner-friendly journey through web foundations, React, production frontend engineering, and interview preparation.

Python Developer Career Path

A practical route through Python fundamentals, automation, backend basics, testing, projects, interview preparation, and career growth.

Fetch API

Master data fetching in React with the Fetch API. Learn patterns for loading states, error handling, cancellation, and the production patterns senior engineers use.

Axios

Master Axios in React — the most popular HTTP client library. Learn instance configuration, interceptors, error handling, and the patterns senior engineers use in enterprise applications.