Suspense
info
- Ensure you're on the latest version of React
- If you use suspense with tRPC's automatic SSR in Next.js, the full page will crash on the server if a query fails, even if you have an
<ErrorBoundary />
Usage
tip
useSuspenseQuery
& useSuspenseInfiniteQuery
both return a [data, query]
-tuple, to make it easy to directly use your data and renaming the variable to something descriptive
useSuspenseQuery()
tsx
// @filename: pages/index.tsximportReact from 'react';import {trpc } from '../utils/trpc';functionPostView () {const [post ,postQuery ] =trpc .post .byId .useSuspenseQuery ({id : '1' });return <>{/* ... */}</>;}
tsx
// @filename: pages/index.tsximportReact from 'react';import {trpc } from '../utils/trpc';functionPostView () {const [post ,postQuery ] =trpc .post .byId .useSuspenseQuery ({id : '1' });return <>{/* ... */}</>;}
useSuspenseInfiniteQuery()
tsx
// @filename: pages/index.tsximport React from 'react';import { trpc } from '../utils/trpc';function PostView() {const [{ pages }, allPostsQuery] = trpc.post.all.useSuspenseInfiniteQuery({},{getNextPageParam(lastPage) {return lastPage.nextCursor;},},);const { isFetching, isFetchingNextPage, fetchNextPage, hasNextPage } =allPostsQuery;return <>{/* ... */}</>;}
tsx
// @filename: pages/index.tsximport React from 'react';import { trpc } from '../utils/trpc';function PostView() {const [{ pages }, allPostsQuery] = trpc.post.all.useSuspenseInfiniteQuery({},{getNextPageParam(lastPage) {return lastPage.nextCursor;},},);const { isFetching, isFetchingNextPage, fetchNextPage, hasNextPage } =allPostsQuery;return <>{/* ... */}</>;}
useSuspenseQueries()
Suspense equivalent of useQueries()
.
tsx
const Component = (props: { postIds: string[] }) => {const [posts, postQueries] = trpc.useSuspenseQueries((t) =>props.postIds.map((id) => t.post.byId({ id })),);return <>{/* [...] */}</>;};
tsx
const Component = (props: { postIds: string[] }) => {const [posts, postQueries] = trpc.useSuspenseQueries((t) =>props.postIds.map((id) => t.post.byId({ id })),);return <>{/* [...] */}</>;};
Prefetching
The preformance of suspense queries can be improved by prefetching the query data before the Suspense component is rendered (this is sometimes called "render-as-you-fetch").
note
- Prefetching and the render-as-you-fetch model are very dependent on the framework and router you are using. We recommend reading your frameworks router docs along with the @tanstack/react-query docs to understand how to implement these patterns.
- If you are using Next.js please look at the docs on Server-Side Helpers to implement server-side prefetching.
Route-level prefetching
tsx
const utils = createTRPCQueryUtils({ queryClient, client: trpcClient });// tanstack router/ react router loaderconst loader = async (params: { id: string }) =>utils.post.byId.ensureQueryData({ id: params.id });
tsx
const utils = createTRPCQueryUtils({ queryClient, client: trpcClient });// tanstack router/ react router loaderconst loader = async (params: { id: string }) =>utils.post.byId.ensureQueryData({ id: params.id });
Component-level prefetching with usePrefetchQuery
tsx
import { trpc } from '../utils/trpc';function PostViewPage(props: { postId: string }) {trpc.post.byId.usePrefetchQuery({ id: props.postId });return (<Suspense><PostView postId={props.postId} /></Suspense>);}
tsx
import { trpc } from '../utils/trpc';function PostViewPage(props: { postId: string }) {trpc.post.byId.usePrefetchQuery({ id: props.postId });return (<Suspense><PostView postId={props.postId} /></Suspense>);}
Component-level prefetching with usePrefetchInfiniteQuery
tsx
import { trpc } from '../utils/trpc';// will have to be passed to the child PostView `useSuspenseInfiniteQuery`export const getNextPageParam = (lastPage) => lastPage.nextCursor;function PostViewPage(props: { postId: string }) {trpc.post.all.usePrefetchInfiniteQuery({}, { getNextPageParam });return (<Suspense><PostView postId={props.postId} /></Suspense>);}
tsx
import { trpc } from '../utils/trpc';// will have to be passed to the child PostView `useSuspenseInfiniteQuery`export const getNextPageParam = (lastPage) => lastPage.nextCursor;function PostViewPage(props: { postId: string }) {trpc.post.all.usePrefetchInfiniteQuery({}, { getNextPageParam });return (<Suspense><PostView postId={props.postId} /></Suspense>);}