跳至主要內容
版本:11.x

伺服器端輔助

伺服器端輔助提供一組輔助函式,可讓您在伺服器上預先擷取查詢。這對 SSG 有用,但如果您選擇不使用 ssr: true,對 SSR 也有用。

透過伺服器端輔助預先擷取可讓查詢快取在伺服器上填入,這表示這些查詢最初不必在前端擷取。

有 2 種方法可以使用伺服器端輔助。

1. 內部路由器

當您有權限存取 tRPC 路由器時,會使用此方法。例如,在開發單體 Next.js 應用程式時。

使用輔助程式可讓 tRPC 直接在伺服器上呼叫你的程序,無需 HTTP 要求,類似於伺服器端呼叫。這也表示你沒有像平常一樣手邊有要求和回應。請務必使用不含 reqres 的內容建立伺服器端輔助程式,這些內容通常會透過內容建立填入。我們建議在這種情況下採用"內部" 和 "外部" 內容的概念。

ts
import { createServerSideHelpers } from '@trpc/react-query/server';
import { createContext } from '~/server/context';
import superjson from 'superjson';
const helpers = createServerSideHelpers({
router: appRouter,
ctx: await createContext(),
transformer: superjson, // optional - adds superjson serialization
});
ts
import { createServerSideHelpers } from '@trpc/react-query/server';
import { createContext } from '~/server/context';
import superjson from 'superjson';
const helpers = createServerSideHelpers({
router: appRouter,
ctx: await createContext(),
transformer: superjson, // optional - adds superjson serialization
});

2. 外部路由器

當你無法直接存取你的 tRPC 路由器時,就會使用此方法。例如,在開發 Next.js 應用程式和獨立 API 分別主機時。

ts
import { createTRPCClient } from '@trpc/client';
import { createServerSideHelpers } from '@trpc/react-query/server';
import superjson from 'superjson';
const proxyClient = createTRPCClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:3000/api/trpc',
}),
],
});
const helpers = createServerSideHelpers({
client: proxyClient,
});
ts
import { createTRPCClient } from '@trpc/client';
import { createServerSideHelpers } from '@trpc/react-query/server';
import superjson from 'superjson';
const proxyClient = createTRPCClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:3000/api/trpc',
}),
],
});
const helpers = createServerSideHelpers({
client: proxyClient,
});

輔助程式使用

伺服器端輔助程式方法會傳回一個物件,很像 tRPC 客戶端,其中包含你的所有路由器作為金鑰。不過,你會取得 prefetchfetchprefetchInfinitefetchInfinite 函式,而不是 useQueryuseMutation

prefetchfetch 之間的主要差異在於,fetch 的作用很像一般函式呼叫,傳回查詢的結果,而 prefetch 既不會傳回結果,也不會引發例外 - 如果你需要這種行為,請改用 fetch。相反地,prefetch 會將查詢新增到快取中,你會先將其脫水,然後傳送到客戶端。

ts
return {
props: {
// very important - use `trpcState` as the key
trpcState: helpers.dehydrate(),
},
};
ts
return {
props: {
// very important - use `trpcState` as the key
trpcState: helpers.dehydrate(),
},
};

經驗法則為,對於你已知在客戶端會需要的查詢,請使用 prefetch,而對於你想要在伺服器上使用其結果的查詢,請使用 fetch

這些函式都是 react-query 函式的包裝器。請查看其文件,以詳細瞭解它們。

資訊

如需完整範例,請參閱我們的E2E SSG 測試範例

Next.js 範例

pages/posts/[id].tsx
tsx
import { createServerSideHelpers } from '@trpc/react-query/server';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import { appRouter } from 'server/routers/_app';
import superjson from 'superjson';
import { trpc } from 'utils/trpc';
export async function getServerSideProps(
context: GetServerSidePropsContext<{ id: string }>,
) {
const helpers = createServerSideHelpers({
router: appRouter,
ctx: {},
transformer: superjson,
});
const id = context.params?.id as string;
/*
* Prefetching the `post.byId` query.
* `prefetch` does not return the result and never throws - if you need that behavior, use `fetch` instead.
*/
await helpers.post.byId.prefetch({ id });
// Make sure to return { props: { trpcState: helpers.dehydrate() } }
return {
props: {
trpcState: helpers.dehydrate(),
id,
},
};
}
export default function PostViewPage(
props: InferGetServerSidePropsType<typeof getServerSideProps>,
) {
const { id } = props;
const postQuery = trpc.post.byId.useQuery({ id });
if (postQuery.status !== 'success') {
// won't happen since the query has been prefetched
return <>Loading...</>;
}
const { data } = postQuery;
return (
<>
<h1>{data.title}</h1>
<em>Created {data.createdAt.toLocaleDateString()}</em>
<p>{data.text}</p>
<h2>Raw data:</h2>
<pre>{JSON.stringify(data, null, 4)}</pre>
</>
);
}
pages/posts/[id].tsx
tsx
import { createServerSideHelpers } from '@trpc/react-query/server';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import { appRouter } from 'server/routers/_app';
import superjson from 'superjson';
import { trpc } from 'utils/trpc';
export async function getServerSideProps(
context: GetServerSidePropsContext<{ id: string }>,
) {
const helpers = createServerSideHelpers({
router: appRouter,
ctx: {},
transformer: superjson,
});
const id = context.params?.id as string;
/*
* Prefetching the `post.byId` query.
* `prefetch` does not return the result and never throws - if you need that behavior, use `fetch` instead.
*/
await helpers.post.byId.prefetch({ id });
// Make sure to return { props: { trpcState: helpers.dehydrate() } }
return {
props: {
trpcState: helpers.dehydrate(),
id,
},
};
}
export default function PostViewPage(
props: InferGetServerSidePropsType<typeof getServerSideProps>,
) {
const { id } = props;
const postQuery = trpc.post.byId.useQuery({ id });
if (postQuery.status !== 'success') {
// won't happen since the query has been prefetched
return <>Loading...</>;
}
const { data } = postQuery;
return (
<>
<h1>{data.title}</h1>
<em>Created {data.createdAt.toLocaleDateString()}</em>
<p>{data.text}</p>
<h2>Raw data:</h2>
<pre>{JSON.stringify(data, null, 4)}</pre>
</>
);
}