useActorSuspenseQuery
useActorSuspenseQuery is a React hook for fetching data from canisters with Suspense support. It suspends the component until data is available, eliminating the need for loading state handling.
Import
Section titled “Import”import { createActorHooks } from "@ic-reactor/react"
const { useActorSuspenseQuery } = createActorHooks(backend)import { Suspense } from "react"
function UserProfile({ userId }: { userId: string }) { // This hook suspends until data is loaded const { data } = useActorSuspenseQuery({ functionName: "getUser", args: [userId], })
// data is ALWAYS defined here - no undefined check needed return ( <div> <h1>{data.name}</h1> <p>{data.email}</p> </div> )}
// Must be wrapped in Suspensefunction App() { return ( <Suspense fallback={<Loading />}> <UserProfile userId="user-123" /> </Suspense> )}Options
Section titled “Options”Same as useActorQuery except:
Key Options
Section titled “Key Options”| Option | Type | Default | Description |
|---|---|---|---|
functionName | string | Required | The canister method to call |
args | array | [] | Arguments to pass to the method |
staleTime | number | 0 | Time in ms before data is considered stale |
select | function | - | Transform the data before returning |
Return Value
Section titled “Return Value”Returns a TanStack Query suspense result. The key difference from useActorQuery:
| Property | Type | Description |
|---|---|---|
data | TData | Always defined (never undefined) |
error | never | Errors are thrown, not returned |
status | 'success' | Always success (suspends otherwise) |
Examples
Section titled “Examples”Basic Suspense Query
Section titled “Basic Suspense Query”function Greeting() { const { data } = useActorSuspenseQuery({ functionName: "greet", args: ["World"], })
// data is guaranteed to be defined return <h1>{data}</h1>}
function App() { return ( <Suspense fallback={<div>Loading...</div>}> <Greeting /> </Suspense> )}Multiple Suspense Queries
Section titled “Multiple Suspense Queries”function Dashboard({ userId }: { userId: string }) { // Both queries run in parallel const { data: user } = useActorSuspenseQuery({ functionName: "getUser", args: [userId], })
const { data: stats } = useActorSuspenseQuery({ functionName: "getUserStats", args: [userId], })
return ( <div> <h1>Welcome, {user.name}</h1> <Stats data={stats} /> </div> )}With Select
Section titled “With Select”const { data: userName } = useActorSuspenseQuery({ functionName: "getUser", args: [userId], select: (user) => user.name, // data is just the name string})
return <h1>Hello, {userName}</h1>Nested Suspense Boundaries
Section titled “Nested Suspense Boundaries”function App() { return ( <Suspense fallback={<PageSkeleton />}> <Header /> {/* Has its own data */} <Suspense fallback={<ContentSkeleton />}> <MainContent /> {/* Independent loading */} </Suspense> <Suspense fallback={<SidebarSkeleton />}> <Sidebar /> {/* Independent loading */} </Suspense> </Suspense> )}Error Handling with Error Boundaries
Section titled “Error Handling with Error Boundaries”import { ErrorBoundary } from "react-error-boundary"
function ErrorFallback({ error, resetErrorBoundary }) { return ( <div className="error"> <p>Something went wrong:</p> <pre>{error.message}</pre> <button onClick={resetErrorBoundary}>Try again</button> </div> )}
function App() { return ( <ErrorBoundary FallbackComponent={ErrorFallback}> <Suspense fallback={<Loading />}> <UserProfile userId="user-123" /> </Suspense> </ErrorBoundary> )}With Stale Time
Section titled “With Stale Time”const { data } = useActorSuspenseQuery({ functionName: "getConfig", args: [], staleTime: 5 * 60 * 1000, // Fresh for 5 minutes})Sequential Suspense (Waterfall)
Section titled “Sequential Suspense (Waterfall)”function UserPosts({ userId }: { userId: string }) { // This query runs first const { data: user } = useActorSuspenseQuery({ functionName: "getUser", args: [userId], })
// This query runs after user is loaded const { data: posts } = useActorSuspenseQuery({ functionName: "getUserPosts", args: [user.id], // Uses data from first query })
return <PostList posts={posts} author={user.name} />}When to Use Suspense
Section titled “When to Use Suspense”✅ Use Suspense when:
- You always need the data (no conditional fetching)
- You want cleaner components without loading state
- You’re using React Server Components
- You want loading states at the boundary level
❌ Use regular useActorQuery when:
- You need conditional fetching (
enabledoption) - You want per-component loading UI
- You need to access
isPendingorisFetchingstates
See Also
Section titled “See Also”- useActorQuery — Regular query hook
- useActorSuspenseInfiniteQuery — Suspense pagination
- Queries Guide — In-depth query patterns
- createActorHooks — Creating hooks