{
const url = pageParam
? `/api/users?cursor=${pageParam}`
: '/api/users';
const response = await fetch(url);
return response.json();
}
export function useInfiniteUsers() {
return useInfiniteQuery({
queryKey: ['users', 'infinite'],
queryFn: fetchUsersPage,
initialPageParam: undefined,
getNextPageParam: (lastPage) => lastPage.nextCursor,
getPreviousPageParam: (firstPage) => firstPage.previousCursor,
});
}
// Usage in component
function UserList() {
const {
data,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
} = useInfiniteUsers();
return (
{data?.pages.map((page, i) => (
{page.data.map((user) => (
))}
))}
);
}
```
### Prefetching
```typescript
import { useQueryClient } from '@tanstack/react-query';
function UserLink({ userId }: { userId: string }) {
const queryClient = useQueryClient();
const prefetchUser = () => {
queryClient.prefetchQuery({
queryKey: ['users', userId],
queryFn: () => fetchUser(userId),
staleTime: 1000 * 60 * 5,
});
};
return (
View User
);
}
```
### Query Keys Factory
```typescript
export const userKeys = {
all: ['users'] as const,
lists: () => [...userKeys.all, 'list'] as const,
list: (filters: Filters) => [...userKeys.lists(), filters] as const,
details: () => [...userKeys.all, 'detail'] as const,
detail: (id: string) => [...userKeys.details(), id] as const,
};
// Usage
useQuery({ queryKey: userKeys.detail(userId), ... });
queryClient.invalidateQueries({ queryKey: userKeys.lists() });
```
## Best Practices
- Use query key factories for consistency
- Set appropriate staleTime for your data
- Implement optimistic updates for better UX
- Use placeholderData or initialData strategically
- Separate server state from client state
## Target Processes
- react-application-development
- nextjs-full-stack
- data-fetching-setup
- performance-optimization