tanstack-react-query

📁 gilbertopsantosjr/fullstacknextjs 📅 12 days ago
4
总安装量
4
周安装量
#54002
全站排名
安装命令
npx skills add https://github.com/gilbertopsantosjr/fullstacknextjs --skill tanstack-react-query

Agent 安装分布

opencode 2
cursor 2
codex 2
gemini-cli 2
replit 1

Skill 文档

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

  1. Query Keys: Use hierarchical keys; invalidate broadly, fetch specifically
  2. Mutations: Always invalidate or update related queries on success
  3. Loading States: Use isLoading for first load, isFetching for background updates
  4. Error Handling: Handle in onError callback; show user-friendly messages
  5. Optimistic Updates: Use for high-confidence mutations; always implement rollback
  6. Conditional Queries: Use enabled option, not conditional hook calls
  7. Derived Data: Use select to transform data; keeps original in cache

References

Detailed patterns and examples:

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