AI Skill Library

TanStack Query

Server state management: queries, mutations, caching, pagination, optimistic updates.

reactdata-fetchingfrontend
# TanStack Query

## Install
```bash
npm install @tanstack/react-query
```

## Setup
```tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const queryClient = new QueryClient({
  defaultOptions: { queries: { staleTime: 1000 * 60 } },
})
<QueryClientProvider client={queryClient}>
  <App />
</QueryClientProvider>
```

## useQuery
```tsx
const { data, isLoading, isError, error, refetch } = useQuery({
  queryKey: ['users', userId],    // cache key
  queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),
  staleTime: 1000 * 60 * 5,      // fresh for 5 min
  gcTime: 1000 * 60 * 10,        // cache 10 min after last use
  enabled: !!userId,              // conditional fetch
  retry: 3,
  select: (data) => data.users,  // transform
})
```

## useMutation
```tsx
const mutation = useMutation({
  mutationFn: (newUser) => fetch('/api/users', {
    method: 'POST', body: JSON.stringify(newUser),
  }).then(r => r.json()),
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ['users'] })
  },
  onError: (error) => console.error(error),
})

mutation.mutate({ name: 'Alice' })
// or async:
await mutation.mutateAsync({ name: 'Bob' })
```

## Optimistic updates
```tsx
onMutate: async (newUser) => {
  await queryClient.cancelQueries({ queryKey: ['users'] })
  const previous = queryClient.getQueryData(['users'])
  queryClient.setQueryData(['users'], (old) => [...old, newUser])
  return { previous }  // rollback context
},
onError: (err, vars, ctx) => {
  queryClient.setQueryData(['users'], ctx.previous)
},
```

## Pagination
```tsx
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
  queryKey: ['posts'],
  queryFn: ({ pageParam = 1 }) => fetchPosts(pageParam),
  getNextPageParam: (lastPage) => lastPage.nextCursor,
})
// data.pages is array of pages; data.pages.flatMap(p => p.items)
```

## Prefetch
```tsx
await queryClient.prefetchQuery({
  queryKey: ['user', id],
  queryFn: () => fetchUser(id),
})
// Next.js: call in Server Component, pass dehydrated state to client
```

## DevTools
```tsx
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
<ReactQueryDevtools initialIsOpen={false} />
```

API: /api/skills/tanstack-query