tanstack-query-core
Use when asking about "TanStack Query", "React Query", "useQuery", "query keys", "staleTime", "query client setup", "query factories", or "queryOptions"
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
TanStack Query Core
Core Mental Model
TanStack Query is an async state manager, not a data fetching library.
- Manages async state through Promises
- Data fetching happens in
queryFn(axios, fetch, etc.) - Synchronizes data using unique
QueryKeyidentifiers
Critical rule: Use exclusively for async/server state. Use local state for UI state.
Query Options API (v5+)
Use queryOptions() for type safety and reusability:
import { queryOptions, useQuery } from "@tanstack/react-query";
// Define reusable query options
const todoQueryOptions = (id: string) =>
queryOptions({
queryKey: ["todos", id],
queryFn: () => fetchTodo(id),
staleTime: 5 * 60 * 1000, // 5 minutes
});
// Usage
const { data } = useQuery(todoQueryOptions(id));
Query Factories
Organize related queries:
export const todoQueries = {
all: () => queryOptions({ queryKey: ["todos"], queryFn: fetchAllTodos }),
detail: (id: string) =>
queryOptions({
queryKey: ["todos", id],
queryFn: () => fetchTodo(id),
staleTime: 5 * 60 * 1000,
}),
};
// Usage
const { data } = useQuery(todoQueries.detail(id));
staleTime Configuration
staleTime is the most important option:
- Fresh data (within staleTime): Cache only, no refetch
- Stale data (beyond staleTime): Cache + background refetch
// Recommended defaults
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000, // 1 minute default
gcTime: 5 * 60 * 1000, // 5 minutes cleanup
refetchOnWindowFocus: true,
refetchOnReconnect: true,
},
},
});
Query Keys as Dependencies
Always include parameters in queryKey:
// CORRECT: Parameters in queryKey
const todoQuery = (id: string) =>
queryOptions({
queryKey: ["todos", id], // ✅ id included
queryFn: () => fetchTodo(id),
});
// INCORRECT: Missing id in queryKey
const todoQuery = (id: string) =>
queryOptions({
queryKey: ["todos"], // ❌ id missing
queryFn: () => fetchTodo(id),
});
Common Anti-Patterns
1. Parameters to refetch()
// WRONG: refetch({ id: newId }) - doesn't work
// CORRECT: Use state to trigger new query
const [todoId, setTodoId] = useState(id);
const { data } = useQuery(todoQuery(todoId));
setTodoId(newId); // Triggers new query
2. Client State in RQ
// WRONG: UI state in RQ
// CORRECT: Use React state, Zustand, etc.
const [isOpen, setIsOpen] = useState(false); // ✅
3. QueryClient in Component
// WRONG: New client every render
function App() {
const queryClient = new QueryClient(); // ❌
}
// CORRECT: Create once
const queryClient = new QueryClient(); // ✅
Selectors & Suspense
// Fine-grained updates with select
const { data: title } = useQuery({
...productQuery(id),
select: (data) => data.title,
});
// Suspense for guaranteed data
const { data } = useSuspenseQuery(todoQuery(id)); // data is Todo, not undefined
// Wrap with boundary
<Suspense fallback={<Loading />}>
<TodoDetail id={id} />
</Suspense>
Quick Reference
| Concept | Recommendation |
|---|---|
| Query definition | queryOptions() |
| Organization | Query factories |
| staleTime | Start with 60s |
| Parameters | Always in queryKey |
| Client state | Separate from RQ |
| Refetch control | Adjust staleTime |
Related Skills
- tanstack-mutations - Mutations, invalidation
- tanstack-types - Type safety with Zod
- tanstack-errors - Error handling
- tanstack-forms - Forms integration
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-26
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!