React Query Cache Utilities
SkillDev toolsUse TanStack React Query with auto-generated hooks from @repo/api-client (preferred) or a centralized QueryKeys enum and cache utility for manual setup
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the React Query Cache Utilities skill
What this skill tells your AI
The instructions your AI receives, as published by cliqrelay/cliqrelay in .agents/skills/frontend/react-query-cache-utilities/SKILL.md and read by ahel’s review.
This skill covers
@tanstack/react-query.
This project uses React Query (@tanstack/react-query) for server state caching. There are two patterns:
- Auto-generated hooks from
@repo/api-client— preferred for covered domains - Manual setup — for domains not covered by
@repo/api-client
Pattern A: Auto-generated Hooks from @repo/api-client (Preferred)
For domains covered by @repo/api-client, all React Query hooks are auto-generated by Orval:
// Extension app — in a component
import { useGetAllGuides, useCreateGuide, useDeleteGuide } from "@repo/api-client";
function GuideList() {
// Query hook with auto-generated query keys, caching, and refetching
const { data, isLoading, error } = useGetAllGuides();
// Mutation hook with auto-generated invalidate logic
const deleteMutation = useDeleteGuide({
mutation: {
onSuccess: () => {
showToastSuccess("Guide deleted");
},
onError: (error) => {
showToastError("Error", error.message);
},
},
});
// ...
}
✅ DO — Use auto-generated hooks as the primary pattern
✅ DO — Use standard TanStack Query patterns (loading, error, success callbacks)
❌ DON'T — Write manual query hooks for domains covered by @repo/api-client
Pattern B: Manual Setup (Non-api-client Domains)
For domains not covered by @repo/api-client, use manual React Query setup:
useQuery/useMutation— for component-level data fetchingfetchCachedDataOrFetchNewQuery— for app boot hydration into Zustand storesQueryKeys— centralized enum for all cache keys
Folder Structure
constants/
├── query-keys.ts ← QueryKeys enum ONLY
├── query-client.ts ← QueryClient instance + cache utility
└── env.ts
QueryClient Setup (constants/query-client.ts)
import { QueryClient } from "@tanstack/react-query";
export const queryClient = new QueryClient();
QueryKeys Enum (constants/query-keys.ts)
All cache keys are centralized in a single enum:
// constants/query-keys.ts
export enum QueryKeys {
GET_USER_ME = "get_user_me",
INVENTORY = "inventory",
PRODUCT = "product",
PRODUCTS = "products",
// ...
}
✅ DO — All query keys in the enum, no inline string literals
❌ DON'T — Use string literals as query keys
// ❌ DON'T
useQuery(["get_user_me"], getUserMe);
// ✅ DO
useQuery([QueryKeys.GET_USER_ME], getUserMe);
Cache Utility (constants/query-client.ts)
This utility is used specifically for app boot hydration — loading cached or fresh data into Zustand stores before the first render:
// constants/query-client.ts
export const fetchCachedDataOrFetchNewQuery = async <T>(
queryKey: QueryKey,
queryFn: () => Promise<unknown>
): Promise<T | null> => {
const cachedData: any | undefined = queryClient.getQueryData(queryKey);
if (cachedData) {
return cachedData as T;
}
const fetchedQueryData: any = await queryClient.fetchQuery({
queryKey,
queryFn: async () => {
try {
return await queryFn();
} catch (error: any) {
console.error(error);
return null;
}
},
staleTime: 60 * 1000
});
return fetchedQueryData;
};
Usage: Boot Hydration into Zustand Stores
async function bootstrapApp() {
const userData = await fetchCachedDataOrFetchNewQuery(
[QueryKeys.GET_USER_ME],
getCurrentUser
);
if (userData) {
useSessionStore.getState().setUser(userData);
} else {
useSessionStore.getState().setUser(null);
}
}
When to Use What
| Scenario | Pattern | Tool |
|---|---|---|
| Extension app, api-client covers the domain | Auto-generated hooks | useGetAllGuides, useCreateGuide, etc. |
| Web app, client-side caching needed | Standard React Query | useQuery / useMutation |
| App boot, hydrate store (non-api-client) | Manual cache utility | fetchCachedDataOrFetchNewQuery |
| Invalidating cache (non-api-client) | Manual | queryClient.invalidateQueries() |
Rules
✅ DO
- Use auto-generated hooks from
@repo/api-clientfor covered domains - Put
QueryKeysenum inconstants/query-keys.ts(non-api-client domains) - Put
QueryClient+fetchCachedDataOrFetchNewQueryinconstants/query-client.ts(non-api-client domains) - Use
fetchCachedDataOrFetchNewQueryonly for app boot / context provider hydration - Cache-first: always check cache before network
❌ DON'T
- Don't write manual query hooks for domains covered by
@repo/api-client - Don't use
fetchCachedDataOrFetchNewQueryin components — it's for boot hydration only - Don't inline query key strings — always use
QueryKeys - Don't forget
staleTimewhen usingfetchCachedDataOrFetchNewQuery
Signals
- GitHub stars
- 40
- Forks
- 1
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
react-query-cache-utilities- Source
- github.com/cliqrelay/cliqrelay