Skip to main content

tanstack-query

TanStack Query v5 (React Query) server state management. Use for data fetching, caching, mutations, or encountering v4 migration, stale data, invalidation errors.

来源信息

仓库
secondsky/claude-skills
最近来源活动
2026年8月5日 23:44
检测到的 SKILL.md 语言
英语
星标
231
Forks
32

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

文件资源管理器
34 个文件

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
tanstack-query
description
TanStack Query v5 (React Query) server state management. Use for data fetching, caching, mutations, or encountering v4 migration, stale data, invalidation errors.
metadata
{"keywords":["TanStack Query","React Query","useQuery","useMutation","useInfiniteQuery","useSuspenseQuery","QueryClient","QueryClientProvider","data fetching","server state","caching","staleTime","gcTime","query invalidation","prefetching","optimistic updates","mutations","query keys","query functions","error boundaries","suspense","React Query DevTools","v5 migration","v4 to v5","request waterfalls","background refetching","cacheTime renamed","loading status renamed","pending status","initialPageParam required","keepPreviousData removed","placeholderData","[Truncated]"]}
license
MIT
# TanStack Query (React Query) v5 **Status**: Production Ready ✅ **Last Updated**: 2026-08-03 **Dependencies**: React 18.0+ (18.3+ recommended), TypeScript 4.9+ (5.x preferred) **Latest Versions**: @tanstack/react-query@5.101.4, @tanstack/react-query-devtools@5.101.4, @tanstack/eslint-plugin-query@5.101.4 --- ## Quick Start (5 Minutes) ### 1. Install Dependencies ```bash # choose your package manager pnpm add @tanstack/react-query@latest @tanstack/react-query-devtools@latest # or npm install @tanstack/react-query@latest @tanstack/react-query-devtools@latest # or bun add @tanstack/react-query@latest @tanstack/react-query-devtools@latest ``` **Why this matters:** - TanStack Query v5 requires React 18+ (uses useSyncExternalStore) - DevTools are essential for debugging queries and mutations - v5 has breaking changes from v4 - use latest for all fixes ### 2. Set Up QueryClient Provider ```tsx // src/main.tsx or src/index.tsx import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { ReactQueryDevtools } from '@tanstack/react-query-devtools' import App from './App' // Create a client const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 1000 * 60 * 5, // 5 minutes gcTime: 1000 * 60 * 60, // 1 hour (formerly cacheTime) retry: 1, refetchOnWindowFocus: false, }, }, }) createRoot(document.getElementById('root')!).render( <StrictMode> <QueryClientProvider client={queryClient}> <App /> <ReactQueryDevtools initialIsOpen={false} /> </QueryClientProvider> </StrictMode> ) ``` **CRITICAL:** - Wrap entire app with `QueryClientProvider` - Configure `staleTime` to avoid excessive refetches (default is 0) - Use `gcTime` (not `cacheTime` - renamed in v5) - DevTools should be inside provider **Know the defaults (v5):** - `staleTime: 0` → data is immediately stale, so refetches on mount/focus unless you raise it - `gcTime: 5 * 60 * 1000` → inactive data is garbage-collected after 5 minutes - `retry: 3` in browsers, `retry: 0` on the server - `refetchOnWindowFocus: true` and `refetchOnReconnect: true` - `networkMode: 'online'` (requests pause while offline). Switch to `'always'` for SSR/prefetch where you don't want cancellation. citeturn1search0turn1search1 ### 3. Create First Query ```tsx // src/hooks/useTodos.ts import { useQuery } from '@tanstack/react-query' type Todo = { id: number title: string completed: boolean } async function fetchTodos(): Promise<Todo[]> { const response = await fetch('/api/todos') if (!response.ok) { throw new Error('Failed to fetch todos') } return response.json() } export function useTodos() { return useQuery({ queryKey: ['todos'], queryFn: fetchTodos, }) } // Usage in component: function TodoList() { const { data, isPending, isError, error } = useTodos() if (isPending) return <div>Loading...</div> if (isError) return <div>Error: {error.message}</div> return ( <ul> {data.map(todo => ( <li key={todo.id}>{todo.title}</li> ))} </ul> ) } ``` **CRITICAL:** - v5 requires object syntax: `useQuery({ queryKey, queryFn })` - Use `isPending` (not `isLoading` - that now means "pending AND fetching") - Always throw errors in queryFn for proper error handling - QueryKey should be array for consistent cache keys ### 4. Create First Mutation ```tsx // src/hooks/useAddTodo.ts import { useMutation, useQueryClient } from '@tanstack/react-query' type NewTodo = { title: string } async function addTodo(newTodo: NewTodo) { const response = await fetch('/api/todos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newTodo), }) if (!response.ok) throw new Error('Failed to add todo') return response.json() } export function useAddTodo() { const queryClient = useQueryClient() return useMutation({ mutationFn: addTodo, onSuccess: () => { // Invalidate and refetch todos queryClient.invalidateQueries({ queryKey: ['todos'] }) }, }) } // Usage in component: function AddTodoForm() { const { mutate, isPending } = useAddTodo() const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault() const formData = new FormData(e.currentTarget) mutate({ title: formData.get('title') as string }) } return ( <form onSubmit={handleSubmit}> <input name="title" required /> <button type="submit" disabled={isPending}> {isPending ? 'Adding...' : 'Add Todo'} </button> </form> ) } ``` **Why this works:** - Mutations use callbacks (`onSuccess`, `onError`, `onSettled`) - queries don't - `invalidateQueries` triggers background refetch - Mutations don't cache by default (correct behavior) --- ## The 7-Step Setup Process ### Step 1: Install Dependencies ```bash # Core library (required) pnpm add @tanstack/react-query # DevTools (highly recommended for development) pnpm add -D @tanstack/react-query-devtools # Optional: ESLint plugin for best practices pnpm add -D @tanstack/eslint-plugin-query ``` **Package roles:** - `@tanstack/react-query` - Core React hooks and QueryClient - `@tanstack/react-query-devtools` - Visual debugger (dev only, tree-shakeable) - `@tanstack/eslint-plugin-query` - Catches common mistakes **Version requirements:** - React 18.0 or higher (uses `useSyncExternalStore`) - TypeScript 5.2+ for best type inference (optional but recommended) ### Step 2: Configure QueryClient ```tsx // src/lib/query-client.ts import { QueryClient } from '@tanstack/react-query' export const queryClient = new QueryClient({ defaultOptions: { queries: { // How long data is considered fresh (won't refetch during this time) staleTime: 1000 * 60 * 5, // 5 minutes // How long inactive data stays in cache before garbage collection gcTime: 1000 * 60 * 60, // 1 hour (v5: renamed from cacheTime) // Retry failed requests (0 on server, 3 on client by default) retry: (failureCount, error) => { if (error instanceof Response && error.status === 404) return false return failureCount < 3 }, // Refetch on window focus (can be annoying during dev) refetchOnWindowFocus: false, // Refetch on network reconnect refetchOnReconnect: true, // Refetch on component mount if data is stale refetchOnMount: true, }, mutations: { // Retry mutations on failure (usually don't want this) retry: 0, }, }, }) ``` **Key configuration decisions:** **staleTime vs gcTime:** - `staleTime`: How long until data is considered "stale" and might refetch - `0` (default): Data is immediately stale, refetches on mount/focus - `1000 * 60 * 5`: Data fresh for 5 min, no refetch during this time - `Infinity`: Data never stale, manual invalidation only - `gcTime`: How long unused data stays in cache - `1000 * 60 * 5` (default): 5 minutes - `Infinity`: Never garbage collect (memory leak risk) **When to refetch:** - `refetchOnWindowFocus: true` - Good for frequently changing data (stock prices) - `refetchOnWindowFocus: false` - Good for stable data or during development - `refetchOnMount: true` - Ensures fresh data when component mounts - `refetchOnReconnect: true` - Refetch after network reconnect ### Step 3: Wrap App with Provider ```tsx // src/main.tsx import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import { QueryClientProvider } from '@tanstack/react-query' import { ReactQueryDevtools } from '@tanstack/react-query-devtools' import { queryClient } from './lib/query-client' import App from './App' createRoot(document.getElementById('root')!).render( <StrictMode> <QueryClientProvider client={queryClient}> <App /> <ReactQueryDevtools initialIsOpen={false} buttonPosition="bottom-right" /> </QueryClientProvider> </StrictMode> ) ``` **Provider placement:** - Must wrap all components that use TanStack Query hooks - DevTools must be inside provider - Only one QueryClient instance for entire app **DevTools configuration:** - `initialIsOpen={false}` - Collapsed by default - `buttonPosition="bottom-right"` - Where to show toggle button - Automatically removed in production builds (tree-shaken) ### Advanced Setup (Steps 4-7) **For detailed patterns**: Load `references/advanced-setup.md` when implementing custom query hooks, mutations with optimistic updates, DevTools configuration, or error boundaries. **Quick summaries:** **Step 4: Custom Query Hooks** - Use `queryOptions` factory for reusable patterns. Create custom hooks that encapsulate API calls. **Step 5: Mutations** - Use `useMutation` with `onSuccess` to invalidate queries. For instant UI feedback, implement optimistic updates with `onMutate`/`onError`/`onSettled` pattern. **Step 6: DevTools** - Already included in Step 3. Advanced options for customization available in reference. **Step 7: Error Boundaries** - Use `QueryErrorResetBoundary` with React Error Boundary. Configure `throwOnError` option for global vs local error handling. --- ## Critical Rules ### Always Do ✅ **Use object syntax for all hooks** ```tsx // v5 ONLY supports this: useQuery({ queryKey, queryFn, ...options }) useMutation({ mutationFn, ...options }) ``` ✅ **Use array query keys** ```tsx queryKey: ['todos'] // List queryKey: ['todos', id] // Detail queryKey: ['todos', { filter }] // Filtered ``` ✅ **Configure staleTime appropriately** ```tsx staleTime: 1000 * 60 * 5 // 5 min - prevents excessive refetches ``` ✅ **Use isPending for initial loading state** ```tsx if (isPending) return <Loading /> // isPending = no data yet AND fetching ``` ✅ **Throw errors in queryFn** ```tsx if (!response.ok) throw new Error('Failed') ``` ✅ **Invalidate queries after mutations** ```tsx onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['todos'] }) } ``` ✅ **Use queryOptions factory for reusable patterns** ```tsx const opts = queryOptions({ queryKey, queryFn }) useQuery(opts) useSuspenseQuery(opts) prefetchQuery(opts) ``` ✅ **Use gcTime (not cacheTime)** ```tsx gcTime: 1000 * 60 * 60 // 1 hour ``` ✅ **Know your status flags** ```tsx isPending // no data yet, fetch in flight isFetching // any fetch in flight (including refetch) isRefetching // refetch specifically (data already cached) isLoadingError // initial load failed isPaused // networkMode paused (e.g., offline) isFetchingNextPage // useInfiniteQuery loading more ``` ### Never Do ❌ **Never use v4 array/function syntax** ```tsx // v4 (removed in v5): useQuery(['todos'], fetchTodos, options) // ❌ // v5 (correct): useQuery({ queryKey: ['todos'], queryFn: fetchTodos }) // ✅ ``` ❌ **Never use query callbacks (onSuccess, onError, onSettled in queries)** ```tsx // v5 removed these from queries: useQuery({ queryKey: ['todos'], queryFn: fetchTodos, onSuccess: (data) => {}, // ❌ Removed in v5 }) // Use useEffect instead: const { data } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos }) useEffect(() => { if (data) { // Do something } }, [data]) // Or use mutation callbacks (still supported): useMutation({ mutationFn: addTodo, onSuccess: () => {}, // ✅ Still works for mutations }) ``` ❌ **Never use deprecated options** ```tsx // Deprecated in v5: cacheTime: 1000 // ❌ Use gcTime instead isLoading: true // ❌ Meaning changed, use isPending keepPreviousData: true // ❌ Use placeholderData instead onSuccess: () => {} // ❌ Removed from queries useErrorBoundary: true // ❌ Use throwOnError instead ``` ❌ **Never assume isLoading means "no data yet"** ```tsx // v5 changed this: isLoading = isPending && isFetching // ❌ Now means "pending AND fetching" isPending = no data yet // ✅ Use this for initial load ``` ❌ **Never forget initialPageParam for infinite queries**
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看