From harness-claude
Uses useSuspenseQuery to integrate React Suspense and error boundaries with TanStack Query, eliminating manual loading state conditionals.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:tanstack-suspense-modeThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Use useSuspenseQuery to integrate React's Suspense and error boundaries with TanStack Query
Use useSuspenseQuery to integrate React's Suspense and error boundaries with TanStack Query
if (isLoading) return <Spinner />) from componentsuseSuspenseQuery instead of useQuery to opt into suspense mode — the component suspends instead of returning isLoading.useSuspenseQuery in a <Suspense fallback={...}> boundary — without it, React throws an error.useSuspenseQueries (plural) to run multiple suspense queries in parallel — suspends until all resolve.<Suspense> with an error boundary (<ErrorBoundary> from react-error-boundary) to handle query errors.useSuspenseQuery for data that is always needed — use regular useQuery for optional or conditional data.<HydrationBoundary> — the Client Component suspends only if the cache is empty.// With useSuspenseQuery — no loading conditional needed
'use client';
import { useSuspenseQuery } from '@tanstack/react-query';
import { postDetailOptions } from '@/queries/posts';
// This component either renders with data or suspends — never shows partial state
function PostContent({ id }: { id: string }) {
const { data: post } = useSuspenseQuery(postDetailOptions(id));
// data is guaranteed to be defined here — TypeScript knows this
return <article>{post.content}</article>;
}
// Wrapping component manages the Suspense/Error boundaries
import { Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
function PostPage({ id }: { id: string }) {
return (
<ErrorBoundary fallback={<PostError />}>
<Suspense fallback={<PostSkeleton />}>
<PostContent id={id} />
</Suspense>
</ErrorBoundary>
);
}
// Multiple parallel suspense queries — waits for all
import { useSuspenseQueries } from '@tanstack/react-query';
function PostWithRelated({ id }: { id: string }) {
const [{ data: post }, { data: related }] = useSuspenseQueries({
queries: [
postDetailOptions(id),
relatedPostsOptions(id),
],
});
// Both are defined — component suspends until both resolve
return <PostLayout post={post} related={related} />;
}
useSuspenseQuery changes TanStack Query's data contract: instead of returning { data: T | undefined, isLoading, isError }, it returns { data: T } — data is always defined when the component renders. The component suspends (pauses rendering) until the data is available, and throws errors to the nearest error boundary.
Type safety improvement: With regular useQuery, data is typed as T | undefined — requiring null checks everywhere. With useSuspenseQuery, data is typed as T — no null checks needed because the component cannot render without data.
Suspense boundary placement: Multiple useSuspenseQuery calls in the same component all contribute to the same Suspense boundary. They suspend sequentially (each waits for the previous before starting) unless you use useSuspenseQueries which starts all fetches in parallel.
Sequential vs parallel suspension: Two useSuspenseQuery calls in one component create a waterfall — the second query does not start until the first resolves (because the component re-renders after each suspension). Use useSuspenseQueries to start all in parallel.
Error handling: useSuspenseQuery throws errors to the nearest React error boundary — unlike regular useQuery which catches errors internally and returns them as { isError, error }. Always pair <Suspense> with an <ErrorBoundary> when using suspense mode.
Next.js App Router: Suspense queries work naturally with Next.js streaming — the <Suspense> boundary streams its fallback first, then streams the resolved content. Combined with server-side prefetching via <HydrationBoundary>, the component only suspends on cold cache misses.
https://tanstack.com/query/latest/docs/framework/react/guides/suspense
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeDeclaratively handles async loading states with React Suspense boundaries for lazy-loaded components and Suspense-enabled data fetching.
Manages server state with automatic caching, background refetching, pagination, infinite scrolling, and optimistic updates for React, Vue, Svelte, Angular apps.
Provides TanStack Query v5 reference for React data fetching, caching, server state management using useQuery/useMutation hooks, QueryClient setup, optimistic updates, Next.js SSR/hydration, testing, TypeScript, and advanced patterns.