Install any skill in seconds. Free to start, no credit card required.
Get Started Free →TanStack Query v5 patterns and common pitfalls. Use when implementing data fetching, cache invalidation, or debugging stale data issues. Triggers on: useQuery, useMutation, queryKey, invalidate, TanStack, React Query.
.claude/skills/aiskillstore-pitfalls-tanstack-query/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 140% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 148% | 0% |
| case-03 | ✗→✓ | ▲ Improved | -7% | 0% |
| case-13 | ✗→✓ | ▲ Improved | -19% | 0% |
| case-20 | ✗→✓ | ▲ Improved | -12% | 0% |
Common pitfalls and correct patterns for TanStack Query v5.
Verify query keys use full URL paths for proper deduplication.
Ensure mutations invalidate relevant queries on success.
Verify v5-specific patterns (isPending vs isLoading).
typescript// ✅ CORRECT: Full URL path in queryKey const { data } = useQuery({ queryKey: ['/api/strategies', strategyId], queryFn: () => api.get(`/api/strategies/${strategyId}`), }); // ✅ CORRECT: Invalidate after mutation const mutation = useMutation({ mutationFn: (data) => api.post('/api/strategies', data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['strategies'] }); }, }); // ✅ CORRECT: Type responses with schema types import type { Strategy } from '@shared/schema'; const { data } = useQuery<{ data: Strategy[] }>(...);
typescript// ❌ WRONG: Short queryKey queryKey: ['strategy'] // Won't dedupe properly // ❌ WRONG: Forgetting to invalidate onSuccess: () => { navigate('/'); } // Stale cache! // ❌ WRONG: Using isLoading for mutations mutation.isLoading // Use isPending in v5
typescript// ✅ Update UI immediately, rollback on error const mutation = useMutation({ mutationFn: updateStrategy, onMutate: async (newData) => { await queryClient.cancelQueries({ queryKey: ['strategy', id] }); const previous = queryClient.getQueryData(['strategy', id]); // Optimistic update queryClient.setQueryData(['strategy', id], newData); return { previous }; }, onError: (err, newData, context) => { // Rollback on error queryClient.setQueryData(['strategy', id], context.previous); toast.error('Update failed'); }, onSettled: () => { queryClient.invalidateQueries({ queryKey: ['strategy', id] }); }, });
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 7,596 | 16,454 | +117% | 1 | 1 | 0% | 1,124 | 2,698 | +140% | 0 | 0 | — |
case-02 | fail→pass | 6,438 | 9,442 | +47% | 1 | 1 | 0% | 958 | 2,380 | +148% | 0 | 0 | — |
case-03 | fail→pass | 19,098 | 18,885 | -1% | 1 | 1 | 0% | 3,707 | 3,434 | -7% | 0 | 0 | — |
case-04 | pass→pass | 17,623 | 16,056 | -9% | 1 | 1 | 0% | 2,510 | 2,596 | +3% | 0 | 0 | — |
case-05 | pass→pass | 18,399 | 15,835 | -14% | 1 | 1 | 0% | 2,415 | 2,724 | +13% | 0 | 0 | — |
case-06 | pass→pass | 19,248 | 18,083 | -6% | 1 | 1 | 0% | 2,689 | 2,961 | +10% | 0 | 0 | — |
case-07 | pass→pass | 14,719 | 11,406 | -23% | 1 | 1 | 0% | 2,691 | 2,954 | +10% | 0 | 0 | — |
case-08 | fail→fail | 18,189 | 12,496 | -31% | 1 | 1 | 0% | 2,627 | 2,032 | -23% | 0 | 0 | — |
case-09 | pass→pass | 13,329 | 7,950 | -40% | 1 | 1 | 0% | 1,695 | 1,816 | +7% | 0 | 0 | — |
case-10 | pass→pass | 11,182 | 9,729 | -13% | 1 | 1 | 0% | 1,109 | 1,469 | +32% | 0 | 0 | — |
case-11 | pass→pass | 17,440 | 8,837 | -49% | 1 | 1 | 0% | 2,225 | 2,515 | +13% | 0 | 0 | — |
case-12 | pass→pass | 14,726 | 5,364 | -64% | 1 | 1 | 0% | 1,969 | 1,648 | -16% | 0 | 0 | — |
case-13 | fail→pass | 21,167 | 13,067 | -38% | 1 | 1 | 0% | 2,827 | 2,279 | -19% | 0 | 0 | — |
case-14 | pass→pass | 4,966 | 7,740 | +56% | 1 | 1 | 0% | 537 | 1,063 | +98% | 0 | 0 | — |
case-15 | pass→pass | 13,421 | 13,341 | -1% | 1 | 1 | 0% | 1,274 | 1,844 | +45% | 0 | 0 | — |
case-16 | pass→pass | 10,052 | 14,606 | +45% | 1 | 1 | 0% | 2,095 | 2,733 | +30% | 0 | 0 | — |
case-17 | pass→pass | 8,864 | 11,278 | +27% | 1 | 1 | 0% | 1,744 | 1,710 | -2% | 0 | 0 | — |
case-18 | pass→pass | 12,217 | 15,591 | +28% | 1 | 1 | 0% | 2,385 | 2,746 | +15% | 0 | 0 | — |
case-19 | pass→pass | 7,716 | 7,971 | +3% | 1 | 1 | 0% | 1,215 | 2,291 | +89% | 0 | 0 | — |
case-20 | fail→pass | 18,315 | 8,899 | -51% | 1 | 1 | 0% | 2,446 | 2,156 | -12% | 0 | 0 | — |
case-21 | fail→pass | 11,295 | 10,576 | -6% | 1 | 1 | 0% | 2,397 | 1,630 | -32% | 0 | 0 | — |
case-22 | pass→pass | 12,603 | 10,570 | -16% | 1 | 1 | 0% | 1,379 | 1,453 | +5% | 0 | 0 | — |
case-23 | fail→fail | 10,708 | 9,794 | -9% | 1 | 1 | 0% | 998 | 1,410 | +41% | 0 | 0 | — |
case-24 | pass→pass | 24,763 | 13,035 | -47% | 1 | 1 | 0% | 1,438 | 1,766 | +23% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +25 percentage points is the difference between those two pass rates over the 24 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.