The Data Fetching Problem
Every React developer writes this:
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('/api/users').then(r => r.json()).then(setData).catch(setError).finally(() => setLoading(false));
}, []);
No caching. No refetching. No deduplication. No optimistic updates.
TanStack Query handles all of this. One hook. Built-in cache. Automatic refetching.
What TanStack Query Gives You
useQuery — Replace useEffect
import { useQuery } from '@tanstack/react-query';
function Users() {
const { data, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(r => r.json()),
});
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return <ul>{data.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
Cached. Deduped. Auto-refetches on window focus. Background updates.
useMutation — Forms and Actions
const mutation = useMutation({
mutationFn: (newUser) => fetch('/api/users', {
method: 'POST',
body: JSON.stringify(newUser),
}),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] });
},
});
<button onClick={() => mutation.mutate({ name: 'John' })}>
{mutation.isPending ? 'Creating...' : 'Create User'}
</button>
Optimistic Updates
const mutation = useMutation({
mutationFn: updateTodo,
onMutate: async (newTodo) => {
await queryClient.cancelQueries({ queryKey: ['todos'] });
const previous = queryClient.getQueryData(['todos']);
queryClient.setQueryData(['todos'], (old) => [...old, newTodo]);
return { previous };
},
onError: (err, newTodo, context) => {
queryClient.setQueryData(['todos'], context.previous);
},
});
UI updates instantly. Rolls back if the server fails.
Infinite Scroll
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ['posts'],
queryFn: ({ pageParam = 0 }) => fetch(`/api/posts?page=${pageParam}`).then(r => r.json()),
getNextPageParam: (lastPage) => lastPage.nextCursor,
});
Works With Any Framework
React, Vue, Solid, Svelte, Angular — same API, different adapter.
Quick Start
npm install @tanstack/react-query
Why This Matters
Server state (data from APIs) is fundamentally different from client state (UI state). TanStack Query is purpose-built for server state — caching, synchronization, and background updates.
Fetching web data for your queries? Check out my web scraping actors on Apify Store — structured API data. For custom solutions, email spinov001@gmail.com.
Top comments (0)