tanstack-react-query
TanStack React Query Expert
Expert guidance for idiomatic React Query (TanStack Query v5) patterns in React applications, with special focus on ZSA server action integration via @saas4dev/core.
Core Hooks
From @saas4dev/core (Server Actions)
import {
useServerActionQuery,
useServerActionMutation,
useServerActionInfiniteQuery,
} from '@saas4dev/core'
From @tanstack/react-query (Direct API)
import {
useQuery,
useMutation,
useInfiniteQuery,
useQueryClient,
} from '@tanstack/react-query'
Decision Tree
Need to fetch data?
├── From server action → useServerActionQuery
├── From REST/fetch directly → useQuery
└── Paginated/infinite → useServerActionInfiniteQuery or useInfiniteQuery
Need to modify data?
├── From server action → useServerActionMutation
└── From REST/fetch directly → useMutation
After mutation, what cache behavior?
├── Simple: just invalidate → queryClient.invalidateQueries()
├── Update specific item → queryClient.setQueryData()
└── Need instant feedback → Optimistic update pattern
Quick Patterns
Server Action Query
const { data, isLoading } = useServerActionQuery(listUsersAction, {
input: { status: 'active' },
queryKey: ['users', 'list', { status: 'active' }],
})
Server Action Mutation with Invalidation
const queryClient = useQueryClient()
const mutation = useServerActionMutation(createUserAction, {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] })
toast.success('User created')
},
onError: (error) => toast.error(error.message),
})
Optimistic Update
const mutation = useServerActionMutation(updateTodoAction, {
onMutate: async (newData) => {
await queryClient.cancelQueries({ queryKey: ['todos', newData.id] })
const previous = queryClient.getQueryData(['todos', newData.id])
queryClient.setQueryData(['todos', newData.id], (old) => ({ ...old, ...newData }))
return { previous }
},
onError: (err, newData, context) => {
queryClient.setQueryData(['todos', newData.id], context?.previous)
},
onSettled: (data, err, variables) => {
queryClient.invalidateQueries({ queryKey: ['todos', variables.id] })
},
})
Query Key Structure
Hierarchy Pattern
['entity'] // All of entity
['entity', 'list'] // All lists
['entity', 'list', { filters }] // Filtered list
['entity', 'detail', id] // Single item
['entity', id, 'nested'] // Nested resource
Query Key Factory
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,
}
Configuration Defaults
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000, // 1 minute
gcTime: 5 * 60 * 1000, // 5 minutes
retry: 1,
refetchOnWindowFocus: false,
},
},
})
Best Practices
- Query Keys: Use hierarchical keys; invalidate broadly, fetch specifically
- Mutations: Always invalidate or update related queries on success
- Loading States: Use
isLoadingfor first load,isFetchingfor background updates - Error Handling: Handle in
onErrorcallback; show user-friendly messages - Optimistic Updates: Use for high-confidence mutations; always implement rollback
- Conditional Queries: Use
enabledoption, not conditional hook calls - Derived Data: Use
selectto transform data; keeps original in cache
References
Detailed patterns and examples:
- query-patterns.md: Query keys, useQuery, pagination, parallel/dependent queries
- mutation-patterns.md: Mutations, cache invalidation, optimistic updates, rollback
- advanced-patterns.md: Custom hooks, prefetching, SSR hydration, testing
Skill Interface
When using this skill, provide:
{
"apiDescription": "REST/GraphQL endpoints, methods, parameters, response shapes",
"uiScenario": "What the UI needs (e.g., 'List with pagination', 'Edit form with instant feedback')",
"constraints": "React Query v5, fetch vs axios, suspense vs traditional",
"currentCode": "(optional) Existing code to improve"
}
Response includes:
- recommendations: Query keys, hooks, invalidation strategy
- exampleCode: React components/hooks demonstrating patterns
- notes: Why these patterns were chosen
More from gilbertopsantosjr/fullstacknextjs
gs-tanstack-react-query
TanStack React Query for data fetching with Clean Architecture. Queries return DTOs, mutations call server actions. Use when working with useQuery, useMutation, cache invalidation, or integrating ZSA server actions.
9gs-feature-architecture
Guide for implementing features in Clean Architecture OOP with Next.js. Use when planning new features, understanding the 4-layer structure (Domain, Application, Infrastructure, Presentation), or deciding where code should live.
3sst-infra
Guide for AWS serverless infrastructure using SST v3 (Serverless Stack). Use when configuring deployment, creating stacks, managing secrets, setting up CI/CD, or deploying Next.js applications to AWS Lambda with DynamoDB.
2zod-validation
Guide for Zod schema validation patterns in TypeScript. Use when creating validation schemas, defining types, validating forms, API inputs, or handling validation errors.
2gs-sst-infra
Guide for AWS serverless infrastructure using SST v3. Covers DynamoDB, Next.js deployment, Lambda handlers with Clean Architecture adapter pattern, and CI/CD configuration.
2feature-architecture
Guide for implementing features in a layered Next.js full-stack architecture. Use when planning new features, understanding the layer structure (Model, DAL, Service, Actions, Components, Pages), or deciding where code should live.
2