跳至主内容
版本:11.x

Suspense

非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

信息
  • 确保您使用的是最新版本的 React
  • 如果在 Next.js 中使用 tRPC 的_自动_ SSR 时结合 Suspense,那么当查询失败时,整个页面会在服务器端崩溃,即使您已经设置了 <ErrorBoundary />

用法

技巧

useSuspenseQueryuseSuspenseInfiniteQuery 都返回 [data, query] 元组(tuple),便于直接使用数据并为变量赋予更具描述性的名称

useSuspenseQuery()

tsx
import { trpc } from '../utils/trpc';
 
function PostView() {
const [post, postQuery] = trpc.post.byId.useSuspenseQuery({ id: '1' });
 
return <>{/* ... */}</>;
}
tsx
import { trpc } from '../utils/trpc';
 
function PostView() {
const [post, postQuery] = trpc.post.byId.useSuspenseQuery({ id: '1' });
 
return <>{/* ... */}</>;
}

useSuspenseInfiniteQuery()

tsx
import { trpc } from '../utils/trpc';
import type { PostPage } from '../server';
 
function PostView() {
const [{ pages }, allPostsQuery] = trpc.post.all.useSuspenseInfiniteQuery(
{},
{
getNextPageParam(lastPage: PostPage) {
return lastPage.nextCursor;
},
initialCursor: '',
},
);
 
const { isFetching, isFetchingNextPage, fetchNextPage, hasNextPage } =
allPostsQuery;
 
return <>{/* ... */}</>;
}
tsx
import { trpc } from '../utils/trpc';
import type { PostPage } from '../server';
 
function PostView() {
const [{ pages }, allPostsQuery] = trpc.post.all.useSuspenseInfiniteQuery(
{},
{
getNextPageParam(lastPage: PostPage) {
return lastPage.nextCursor;
},
initialCursor: '',
},
);
 
const { isFetching, isFetchingNextPage, fetchNextPage, hasNextPage } =
allPostsQuery;
 
return <>{/* ... */}</>;
}

useSuspenseQueries()

这是 useQueries() 的 Suspense 等效实现。

tsx
import { trpc } from '../utils/trpc';
 
const Component = (props: { postIds: string[] }) => {
const [posts, postQueries] = trpc.useSuspenseQueries((t) =>
props.postIds.map((id) => t.post.byId({ id })),
);
 
return <>{/* [...] */}</>;
};
tsx
import { trpc } from '../utils/trpc';
 
const Component = (props: { postIds: string[] }) => {
const [posts, postQueries] = trpc.useSuspenseQueries((t) =>
props.postIds.map((id) => t.post.byId({ id })),
);
 
return <>{/* [...] */}</>;
};

预加载

通过在 Suspense 组件渲染前预加载查询数据,可以提升 suspense 查询的性能(这种方法有时称为 "边渲染边获取")。

备注
  • 预加载(Prefetching)和边渲染边获取(render-as-you-fetch)模式高度依赖于您所使用的框架和路由器。建议同时阅读您框架的路由器文档以及 @tanstack/react-query 文档 来了解如何实现这些模式
  • 如果您正在使用 Next.js,请查阅 Server-Side Helpers 文档以实现服务器端预加载

路由级预加载

tsx
import { createTRPCQueryUtils } from '@trpc/react-query';
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import { QueryClient } from '@tanstack/react-query';
import type { AppRouter } from './server';
 
const queryClient = new QueryClient();
const trpcClient = createTRPCClient<AppRouter>({ links: [httpBatchLink({ url: 'http://localhost:3000' })] });
const utils = createTRPCQueryUtils({ queryClient, client: trpcClient });
 
// tanstack router/ react router loader
const loader = async (params: { id: string }) =>
utils.post.byId.ensureData({ id: params.id });
tsx
import { createTRPCQueryUtils } from '@trpc/react-query';
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import { QueryClient } from '@tanstack/react-query';
import type { AppRouter } from './server';
 
const queryClient = new QueryClient();
const trpcClient = createTRPCClient<AppRouter>({ links: [httpBatchLink({ url: 'http://localhost:3000' })] });
const utils = createTRPCQueryUtils({ queryClient, client: trpcClient });
 
// tanstack router/ react router loader
const loader = async (params: { id: string }) =>
utils.post.byId.ensureData({ id: params.id });

使用 usePrefetchQuery 实现组件级预加载

tsx
import React, { Suspense } from 'react';
import { trpc } from '../utils/trpc';
 
function PostView(props: { postId: string }) {
return <></>;
}
 
function PostViewPage(props: { postId: string }) {
trpc.post.byId.usePrefetchQuery({ id: props.postId });
 
return (
<Suspense>
<PostView postId={props.postId} />
</Suspense>
);
}
tsx
import React, { Suspense } from 'react';
import { trpc } from '../utils/trpc';
 
function PostView(props: { postId: string }) {
return <></>;
}
 
function PostViewPage(props: { postId: string }) {
trpc.post.byId.usePrefetchQuery({ id: props.postId });
 
return (
<Suspense>
<PostView postId={props.postId} />
</Suspense>
);
}

使用 usePrefetchInfiniteQuery 实现组件级预加载

tsx
import React, { Suspense } from 'react';
import { trpc } from '../utils/trpc';
import type { PostPage } from '../server';
 
function PostView(props: { postId: string }) {
return <></>;
}
 
function PostViewPage(props: { postId: string }) {
trpc.post.all.usePrefetchInfiniteQuery(
{},
{
getNextPageParam(lastPage: PostPage) {
return lastPage.nextCursor;
},
initialCursor: '',
},
);
 
return (
<Suspense>
<PostView postId={props.postId} />
</Suspense>
);
}
tsx
import React, { Suspense } from 'react';
import { trpc } from '../utils/trpc';
import type { PostPage } from '../server';
 
function PostView(props: { postId: string }) {
return <></>;
}
 
function PostViewPage(props: { postId: string }) {
trpc.post.all.usePrefetchInfiniteQuery(
{},
{
getNextPageParam(lastPage: PostPage) {
return lastPage.nextCursor;
},
initialCursor: '',
},
);
 
return (
<Suspense>
<PostView postId={props.postId} />
</Suspense>
);
}