From harness-claude
Chains dependent queries in TanStack Query using enabled flag for sequencing on prior results and useQueries for parallel dynamic lists or conditional fetches.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Chain queries that depend on each other's results using the enabled flag and useQueries
Enables TanStack Query suspense mode via useSuspenseQuery to suspend React components on data load instead of inline loading states, for Suspense boundaries and Next.js App Router streaming.
Implements TanStack Query v5 in React apps for API data fetching, server state caching, mutations, optimistic updates, infinite scroll, streaming AI responses, and tRPC v11 integration.
Provides expertise in TanStack Query for React/Next.js data fetching, caching (staleTime/gcTime), mutations, optimistic updates, cache invalidation, and App Router SSR hydration.
Share bugs, ideas, or general feedback.
Chain queries that depend on each other's results using the enabled flag and useQueries
enabled option to block a query from running until its prerequisite data is available.enabled — falsy values (undefined, null, false, 0) disable the query.useQueries() to run a dynamic list of queries in parallel — pass an array of query option objects.select to transform query data before it becomes the input for a dependent query — keeps transformation logic in the query, not in the component.// Single dependent query — user's posts depend on user ID
function useUserPosts(username: string) {
// Step 1: fetch user by username
const userQuery = useQuery({
queryKey: ['user', username],
queryFn: () => fetchUser(username),
});
// Step 2: fetch posts only after user is loaded
const postsQuery = useQuery({
queryKey: ['posts', 'by-user', userQuery.data?.id],
queryFn: () => fetchPostsByUser(userQuery.data!.id),
enabled: !!userQuery.data?.id, // blocks until user.id is available
});
return {
user: userQuery.data,
posts: postsQuery.data,
isLoading: userQuery.isLoading || postsQuery.isLoading,
};
}
// Parallel queries for a dynamic list — fetch N items simultaneously
function usePostDetails(postIds: string[]) {
return useQueries({
queries: postIds.map((id) => ({
queryKey: ['posts', 'detail', id],
queryFn: () => fetchPost(id),
staleTime: 5 * 60 * 1000,
})),
});
// Returns QueryResult[] — one per ID
}
// Conditional fetch — only when a filter is active
function useFilteredPosts(filter: string | null) {
return useQuery({
queryKey: ['posts', 'filtered', filter],
queryFn: () => fetchFilteredPosts(filter!),
enabled: filter !== null && filter.length > 0,
});
}
TanStack Query executes all queries concurrently by default — each useQuery call starts a fetch immediately when the component mounts. Dependent queries introduce explicit sequencing.
enabled flag behavior: When enabled is false, the query is in pending status with fetchStatus: 'idle' — it has no data and is not fetching. As soon as enabled becomes true (e.g., after the prerequisite query resolves), TanStack Query fetches immediately.
Loading state propagation: A dependent query chain means loading states are sequential — the second query cannot start until the first resolves. The combined loading time is the sum of all fetches, not the max. Evaluate whether the dependency is real (data genuinely needed) or whether a backend endpoint could join the data.
useQueries for dynamic lists: useQueries is the correct API for N dynamic queries. Calling useQuery in a loop violates React's rules of hooks (cannot be inside a conditional or loop). useQueries handles variable-length arrays of query definitions.
select for derived keys: Use select to transform query data before passing it to a dependent query key:
const userId = useQuery({
queryKey: ['auth'],
queryFn: fetchCurrentUser,
select: (user) => user.id, // only re-triggers when ID changes, not whole user object
});
The select function memoizes — dependents only re-render when the selected value changes.
Avoiding waterfalls: On the server side (Next.js Server Components), fetch data in parallel with Promise.all instead of sequential awaits. Client-side dependency chains are sometimes unavoidable (auth token → user data), but server-side waterfalls are always avoidable.
https://tanstack.com/query/latest/docs/framework/react/guides/dependent-queries