メインコンテンツへスキップ
バージョン: 11.x

サーバーサイドヘルパー

非公式ベータ版翻訳

このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →

サーバーサイドヘルパーは、サーバー上でクエリをプリフェッチするために使用できる一連のヘルパー関数を提供します。これはSSGで有用なだけでなく、ssr: trueを使用しない場合のSSRにも役立ちます。

サーバーサイドヘルパーによるプリフェッチでは、クエリキャッシュをサーバー上で事前に埋めることができ、これらのクエリがクライアント側で初期フェッチを必要としないことを意味します。

サーバーサイドヘルパーの2つの使用方法

1. 内部ルーター

この方法は、tRPCルーターに直接アクセスできる場合、例えばモノリシックなNext.jsアプリケーションを開発する際に使用されます。

ヘルパーを使用すると、tRPCはサーバーサイドコールと同様に、HTTPリクエストなしでサーバー上で直接プロシージャを呼び出します。 つまり、通常のようにリクエスト(req)やレスポンス(res)を手元で扱えません。コンテキスト作成時に通常埋められるreqresを含まないコンテキストでサーバーサイドヘルパーを初期化してください。このシナリオでは"内部"と"外部"コンテキストの概念をお勧めします。

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

2. 外部ルーター

この方法は、tRPCルーターに直接アクセスできない場合、例えばNext.jsアプリケーションとスタンドアロンなAPIを別々にホストして開発する場合に使用されます。

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

ヘルパーの使用方法

サーバーサイドヘルパーメソッドは、ルーター構造を反映したオブジェクトを返します。このオブジェクトのキーはすべてのルーターとなりますが、useQueryuseMutationではなく、prefetchfetchprefetchInfinitefetchInfinite関数が提供されます。

prefetchfetchの主な違いは、fetchが通常の関数呼び出しのように動作してクエリ結果を返すのに対し、prefetchは結果を返さず例外もスローしない点です。そのような動作が必要な場合は代わりにfetchを使用してください。prefetchはクエリをキャッシュに追加し、これをデハイドレートしてクライアントに送信します。

ts
// In getServerSideProps / getStaticProps:
const props = {
// very important - use `trpcState` as the key
trpcState: helpers.dehydrate(),
};
ts
// In getServerSideProps / getStaticProps:
const 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 { appRouter } from './server/routers/_app';
import { trpc } from './utils/trpc';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import superjson from 'superjson';
 
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 { appRouter } from './server/routers/_app';
import { trpc } from './utils/trpc';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import superjson from 'superjson';
 
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>
</>
);
}