JH
AboutServicesExperienceCase StudiesBlogsContact
Hire Me
ReactMay 20241 min read

Data Fetching in React With TanStack Query

Replace hand-written useEffect fetching with TanStack Query: caching, loading states, mutations and cache invalidation.

Data Fetching in React With TanStack Query

Why Not Just useEffect?

Fetching in useEffect means writing loading and error state by hand, handling race conditions, and refetching the same data on every mount. TanStack Query handles caching, deduplication, and background refetching for you.

Your First Query

A query needs a unique key and a function that returns a promise. The hook gives you the data along with its loading and error state.

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

export function Projects() {
  const { data, isPending, error } = useQuery({
    queryKey: ['projects'],
    queryFn: () => fetch('/api/projects').then(res => res.json()),
  });

  if (isPending) return <p>Loading...</p>;
  if (error) return <p>Something went wrong.</p>;

  return (
    <ul>
      {data.map(project => (
        <li key={project.id}>{project.name}</li>
      ))}
    </ul>
  );
}

Mutations and Cache Invalidation

After a successful mutation, invalidate the related query so the list refreshes with the new data.

tsx
const queryClient = useQueryClient();

const createProject = useMutation({
  mutationFn: (name: string) =>
    fetch('/api/projects', {
      method: 'POST',
      body: JSON.stringify({ name }),
    }),
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ['projects'] });
  },
});

Tips

  • Use stable, descriptive query keys that include every parameter.
  • Set staleTime to avoid unnecessary refetches.
  • Prefetch on hover for instant navigation.
  • Keep server data in the query cache instead of global state.
Next ArticleNginx Reverse Proxy With Free SSL on Ubuntu