TanStack Query v5 mit Claude Code: Server State Management 2026
TanStack Query v5 ist der Standard fuer Server State in React — Caching, Background-Refetching, optimistische Updates und Synchronisation. Claude Code kennt alle v5-Breaking-Changes und generiert idiomatischen Code.
useQuery v5: Die neuen Patterns
Queriesv5 API-Aenderungen und Best Practices
# Prompt: "Migriere meine React Query v4 Queries zu TanStack Query v5"
// v4 (ALT):
const { data, isLoading } = useQuery(['user', userId], () => fetchUser(userId));
// v5 (NEU) — object-only Syntax!
const { data, isLoading, isFetching } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId),
staleTime: 5 * 60 * 1000, // 5 Minuten
gcTime: 10 * 60 * 1000, // ehemals cacheTime in v4
enabled: !!userId, // Nur fetchen wenn userId vorhanden
placeholderData: keepPreviousData, // v5: importierbar statt keepPreviousData option
});
// Query Options Pattern — wiederverwendbar:
export const userQueryOptions = (userId: string) => queryOptions({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId),
staleTime: 60_000,
});
// Verwendung in Component + Prefetch:
const { data: user } = useQuery(userQueryOptions(userId));
// In Route-Loader (React Router v6):
await queryClient.ensureQueryData(userQueryOptions(userId));
// Select: nur relevante Daten abonnieren
const { data: userName } = useQuery({
...userQueryOptions(userId),
select: (user) => user.name, // Re-render nur wenn Name sich aendert
});
v5 Migration-Tipp: "Migriere alle React Query v4 Hooks zu TanStack Query v5. Erklaere alle Breaking Changes und generiere die neue object-Syntax." Claude Code kennt alle 20+ Breaking Changes von v4 zu v5.
useMutation und Optimistic Updates
MutationsOptimistische Updates und Rollback
# Prompt: "Todo-Liste mit optimistischem Toggle — sofort im UI, Rollback bei Fehler"
const toggleTodo = useMutation({
mutationFn: (todoId: string) => updateTodo(todoId, { completed: true }),
onMutate: async (todoId) => {
// Laufende Refetches stoppen
await queryClient.cancelQueries({ queryKey: ['todos'] });
// Snapshot fuer Rollback
const prev = queryClient.getQueryData<Todo[]>(['todos']);
// Optimistisches Update
queryClient.setQueryData<Todo[]>(['todos'], (old) =>
old?.map(t => t.id === todoId ? { ...t, completed: !t.completed } : t) ?? []
);
return { prev }; // Context fuer onError
},
onError: (err, todoId, context) => {
// Rollback auf Snapshot
queryClient.setQueryData(['todos'], context?.prev);
toast.error('Aktualisierung fehlgeschlagen');
},
onSettled: () => {
// Immer: echte Daten laden
queryClient.invalidateQueries({ queryKey: ['todos'] });
},
});
// v5: mutateAsync fuer await-Verwendung
const handleToggle = async (id: string) => {
try {
await toggleTodo.mutateAsync(id);
toast.success('Aktualisiert!');
} catch (e) {
// Fehler bereits in onError behandelt
}
};
Prefetching in Next.js Server Components
PrefetchHydrationBoundary fuer SSR
// app/users/page.tsx — Server Component
import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query';
export default async function UsersPage() {
const queryClient = new QueryClient();
// Server-seitig prefetchen
await queryClient.prefetchQuery({
queryKey: ['users'],
queryFn: fetchUsers, // Direkter DB-Call auf Server!
});
return (
// Dehydrierter State wird zum Client gesendet
<HydrationBoundary state={dehydrate(queryClient)}>
<UserList /> {/* Client Component — Cache bereits befuellt */}
</HydrationBoundary>
);
}
// UserList.tsx (Client Component) — kein Loading-State!
function UserList() {
const { data: users } = useQuery({
queryKey: ['users'],
queryFn: fetchUsers, // Vom Server hydratisiert — kein Netzwerk-Call!
});
return users?.map(u => <UserCard key={u.id} user={u} />);
}
Infinite Queries: Endloser Scroll
InfiniteuseInfiniteQuery fuer Pagination
# Prompt: "Infinite Scroll Feed mit useInfiniteQuery"
const {
data, fetchNextPage, hasNextPage, isFetchingNextPage
} = useInfiniteQuery({
queryKey: ['feed', filter],
queryFn: ({ pageParam }) => fetchFeed({ cursor: pageParam, limit: 20, filter }),
initialPageParam: undefined as string | undefined,
getNextPageParam: (lastPage) => lastPage.nextCursor, // undefined = kein naechste Seite
getPreviousPageParam: (firstPage) => firstPage.prevCursor,
});
// Alle Posts aus allen Seiten flach:
const posts = data?.pages.flatMap(page => page.posts) ?? [];
// IntersectionObserver Trigger:
const { ref } = useIntersection({
onIntersect: () => { if (hasNextPage) fetchNextPage(); },
});
return (
<div>
{posts.map(p => <PostCard key={p.id} post={p} />)}
<div ref={ref}>{isFetchingNextPage && <Spinner />}</div>
</div>
);
Data Fetching im Kurs
Im Claude Code Mastery Kurs: vollstaendiges TanStack Query v5 Modul mit Migration-Guide, Prefetching-Patterns, Optimistic Updates und Infinite Scroll — inkl. Integration mit Next.js Server Components und tRPC.
14 Tage kostenlos testen →