Data Fetching Libraries

Why You'll Reach for React Query or SWR

Data Fetching Libraries

Hand-rolled `useEffect` + `fetch` covers basics. For real apps, React Query and SWR give you caching, deduping, retries, and revalidation — for free.

4 min read Level 2/5 #react#fetching#react-query
What you'll learn
  • Recognize the pain points of raw `useEffect` fetching
  • Know what React Query / SWR provide
  • Pick when each is the right tool

You’ve seen how to fetch with useEffect + fetch. For an actual app, that approach grows pain quickly:

  • Two components fetching the same data make two requests
  • Tabbing away and back doesn’t refresh stale data
  • Refetching after a mutation requires manual plumbing
  • Loading and error states get repeated everywhere
  • Optimistic updates are tricky

Libraries solve all of this with a small API.

React Query (TanStack Query)

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

function UserCard({ id }) {
  const { data, error, isLoading } = useQuery({
    queryKey: ["user", id],
    queryFn: () => fetch(`/api/users/${id}`).then(r => r.json()),
  });

  if (isLoading) return <p>Loading…</p>;
  if (error)     return <p>Error: {error.message}</p>;
  return <p>{data.name}</p>;
}

You get:

  • Caching — the second UserCard with the same id reads from cache
  • Background refetching — when the user tabs back, refresh stale data
  • Deduping — multiple components asking for the same key make one request
  • Retries — failed requests retry on a backoff
  • Optimistic updates — built-in helpers

Mutations

const queryClient = useQueryClient();

const mutation = useMutation({
  mutationFn: newUser => fetch("/api/users", { method: "POST", body: JSON.stringify(newUser) }),
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ["users"] });
  },
});

<button onClick={() => mutation.mutate(form)}>Save</button>

After the save succeeds, every query that depends on ["users"] refetches automatically.

SWR

Similar idea, smaller API:

import useSWR from "swr";

function UserCard({ id }) {
  const { data, error, isLoading } = useSWR(`/api/users/${id}`, url => fetch(url).then(r => r.json()));
  if (isLoading) return <p>Loading…</p>;
  if (error)     return <p>Error</p>;
  return <p>{data.name}</p>;
}

Pick One

LibraryStrengths
React QueryComprehensive — caching, mutations, devtools, infinite queries, suspense
SWRSmaller, simpler — great fit for read-heavy apps

Pick by what your team prefers. Both are excellent. For new apps, React Query is the more common default.

When You Don’t Need Them

  • Static data that doesn’t change
  • Forms that just submit once
  • Toy apps and demos

For everything else with non-trivial server state — use a library.

Up Next

What about state that isn’t from the server?

State Management →