React Query Auditor
Diagnose and fix React Query runtime issues: stale data, missing updates, cache problems.
When to Use This Skill
| Symptom | Use This Skill |
|---|---|
| UI doesn't update after mutation | Yes - check cache invalidation |
| Data flickers or reverts | Yes - check race conditions |
| Stale data after navigation | Yes - check query keys |
| UI doesn't update after TX | Yes - check TX confirmation handler |
For hook structure issues (types, transformers, file organization), use /hooks-architect instead.
Primary Goal: No Manual Refresh
Users should NEVER need to tap refresh to see the latest data.
After any user action (mutation, transaction, navigation), the UI must automatically reflect the current state.
Relationship with /hooks-architect
These skills are complementary:
| Concern | Skill |
|---|---|
| Hook file structure | /hooks-architect |
| Colocated types | /hooks-architect |
| Transform functions | /hooks-architect |
| Creating new hooks | /hooks-architect |
| Cache invalidation | This skill |
| Stale data debugging | This skill |
| UX update issues | This skill |
| Query key matching | This skill |
Quick Diagnosis
Symptom: UI doesn't update after mutation
Check 1: Is the mutation invalidating queries?
// Look for onSuccess/onSettled callbacks
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ... });
}
Check 2: Are ALL related queries invalidated?
// Updating a course should invalidate:
// - The specific course detail
// - Any list that contains courses
// - Related data (modules, SLTs if they embed course info)
onSuccess: (_, variables) => {
queryClient.invalidateQueries({ queryKey: courseKeys.detail(variables.courseId) });
queryClient.invalidateQueries({ queryKey: courseKeys.lists() }); // Don't forget lists!
};
Check 3: Are query keys matching?
// Mutation uses: courseKeys.detail("abc123")
// Query uses: ["courses", "detail", "abc123"]
// These must match exactly for invalidation to work
Symptom: UI doesn't update after blockchain transaction
Important: TX invalidation happens in transaction components (using hooks from src/hooks/tx/), NOT in API hooks (src/hooks/api/). Look for the invalidation in the component that renders the TX UI.
Check 1: Is there a TX confirmation handler?
// TX components use useTxStream() or useTxWatcher() for confirmation
// Then invalidate API caches in the callback:
const { invalidateAll } = useInvalidateStudentCourses();
// After TX confirms via SSE/polling:
onTxConfirmed: () => {
invalidateAll(); // Refreshes API data to reflect on-chain change
};
Check 2: Are all affected role queries invalidated?
// Blockchain TX may affect multiple roles:
void queryClient.invalidateQueries({ queryKey: courseStudentKeys.all }); // Student's view
void queryClient.invalidateQueries({ queryKey: courseTeacherKeys.all }); // Teacher's view
void queryClient.invalidateQueries({ queryKey: courseKeys.detail(courseId) }); // Public view
Symptom: Other user's view doesn't update
Check: Are cross-role queries invalidated?
// Student submits assignment -> Teacher should see it
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: studentCourseKeys.assignments() });
queryClient.invalidateQueries({ queryKey: teacherCourseKeys.commitments() }); // Teacher's view!
};
Symptom: Data flickers or reverts
Check: Race condition with optimistic updates
// Cancel outgoing refetches before optimistic update
onMutate: async () => {
await queryClient.cancelQueries({ queryKey });
// ... optimistic update
};
Audit Checklist
1. Cache Invalidation
For each mutation, verify:
- •
onSuccessinvalidates the specific entity - •
onSuccessinvalidates related lists - • Cross-role queries are invalidated if applicable
- • Uses
voidprefix for fire-and-forget invalidation
2. Query Keys
For each hook file, verify:
- • Keys factory is exported (
courseKeys,taskKeys, etc.) - • Keys use
as constfor type safety - • Keys follow hierarchy:
all→lists()→detail(id) - • Mutation invalidation uses the same key factory
3. Enabled Conditions
For each query, verify:
- • Auth queries have
enabled: isAuthenticated - • Detail queries have
enabled: !!id - • Dependent queries wait for parent data
4. Error Handling
For each queryFn, verify:
- • Non-OK responses throw meaningful errors
- • 404 returns
nullor[](doesn't throw) - • Network errors are distinguishable from API errors
Quick Scan Commands
# Find all query key patterns grep -rn "queryKey:" src/hooks/api/ # Find mutations without onSuccess grep -rn "useMutation" src/hooks/api/ -A 10 | grep -B 5 "mutationFn" | grep -v "onSuccess" # Find invalidateQueries calls grep -rn "invalidateQueries" src/hooks/api/ # Check for missing enabled conditions grep -rn "useQuery" src/hooks/api/ -A 5 | grep -v "enabled"
Common Issues
Issue 1: Missing List Invalidation
Symptom: Detail page updates, but list page shows old data.
Cause: Mutation only invalidates detail key, not list keys.
Fix:
onSuccess: (_, variables) => {
void queryClient.invalidateQueries({ queryKey: entityKeys.detail(variables.id) });
void queryClient.invalidateQueries({ queryKey: entityKeys.lists() }); // Add this!
};
Issue 2: Query Key Mismatch
Symptom: Invalidation doesn't trigger refetch.
Cause: Hardcoded key doesn't match key factory.
Fix: Always use the exported key factory:
// ❌ Wrong
queryClient.invalidateQueries({ queryKey: ["courses", "detail", id] });
// ✅ Correct
queryClient.invalidateQueries({ queryKey: courseKeys.detail(id) });
Issue 3: Missing TX Invalidation
Symptom: Blockchain TX succeeds but UI doesn't update.
Cause: TX confirmation handler doesn't invalidate queries.
Fix: Add invalidation in TX component's onTxConfirmed:
const { invalidateAll } = useInvalidateCourses();
// After TX confirms
invalidateAll();
Issue 4: Stale Closure in Callback
Symptom: Callback uses old state values.
Cause: Callback captures stale closure.
Fix: Use refs for values needed in callbacks:
const dataRef = useRef(data);
useEffect(() => { dataRef.current = data; }, [data]);
const callback = useCallback(() => {
// Use dataRef.current instead of data
}, []); // Empty deps, uses ref
Hook Reference
For the complete list of hooks and their exports, see /hooks-architect reference.
Current hooks:
- •Course: 10 hook files (COMPLETE)
- •Project: 3 hook files (IN PROGRESS)
Related Skills
| Skill | When to Use |
|---|---|
/hooks-architect | Hook structure, types, creating hooks |
/transaction-auditor | TX schema sync with gateway |
/issue-handler | Route errors to correct repo |
/tx-loop-guide | Test transaction flows end-to-end |
Supporting Documentation
- •react-query-best-practices.md - Detailed patterns for cache invalidation, optimistic updates, and blockchain TX flows
Last Updated: February 5, 2026