サーバーサイドレンダリング
SSR を有効にするには、createTRPCNext
設定コールバックで ssr: true
を設定するだけです。
SSR を有効にすると、tRPC は getInitialProps
を使用してサーバー上のすべてのクエリをプリフェッチします。これは、getServerSideProps
を使用するとこのような問題が発生し、解決は我々の手には負えません。
代わりに、SSR を無効のままにして (デフォルト)、サーバーサイドヘルパーを使用して、getStaticProps
または getServerSideProps
でクエリをプリフェッチすることもできます。
サーバーサイドレンダリングステップ中にクエリを適切に実行するには、config
内に特別なロジックを追加する必要があります
さらに、レスポンスキャッシング
も検討してください。
utils/trpc.tstsx
import { httpBatchLink } from '@trpc/client';import { createTRPCNext } from '@trpc/next';import { ssrPrepass } from '@trpc/next/ssrPrepass';import superjson from 'superjson';import type { AppRouter } from './api/trpc/[trpc]';export const trpc = createTRPCNext<AppRouter>({ssr: true,ssrPrepass,config(opts) {const { ctx } = opts;if (typeof window !== 'undefined') {// during client requestsreturn {links: [httpBatchLink({url: '/api/trpc',}),],};}return {links: [httpBatchLink({// The server needs to know your app's full urlurl: `${getBaseUrl()}/api/trpc`,/*** Set custom request headers on every request from tRPC* @link https://trpc.dokyumento.jp/docs/v10/header*/headers() {if (!ctx?.req?.headers) {return {};}// To use SSR properly, you need to forward client headers to the server// This is so you can pass through things like cookies when we're server-side renderingreturn {cookie: ctx.req.headers.cookie,};},}),],};},});
utils/trpc.tstsx
import { httpBatchLink } from '@trpc/client';import { createTRPCNext } from '@trpc/next';import { ssrPrepass } from '@trpc/next/ssrPrepass';import superjson from 'superjson';import type { AppRouter } from './api/trpc/[trpc]';export const trpc = createTRPCNext<AppRouter>({ssr: true,ssrPrepass,config(opts) {const { ctx } = opts;if (typeof window !== 'undefined') {// during client requestsreturn {links: [httpBatchLink({url: '/api/trpc',}),],};}return {links: [httpBatchLink({// The server needs to know your app's full urlurl: `${getBaseUrl()}/api/trpc`,/*** Set custom request headers on every request from tRPC* @link https://trpc.dokyumento.jp/docs/v10/header*/headers() {if (!ctx?.req?.headers) {return {};}// To use SSR properly, you need to forward client headers to the server// This is so you can pass through things like cookies when we're server-side renderingreturn {cookie: ctx.req.headers.cookie,};},}),],};},});
または、特定のリクエストに応じて SSR を条件付きで実行する場合は、ssr
にコールバックを渡すことができます。このコールバックは、ブール値、またはブール値に解決される Promise を返すことができます
utils/trpc.tstsx
import { httpBatchLink } from '@trpc/client';import { createTRPCNext } from '@trpc/next';import superjson from 'superjson';import type { AppRouter } from './api/trpc/[trpc]';export const trpc = createTRPCNext<AppRouter>({config(opts) {const { ctx } = opts;if (typeof window !== 'undefined') {// during client requestsreturn {links: [httpBatchLink({url: '/api/trpc',}),],};}return {links: [httpBatchLink({// The server needs to know your app's full urlurl: `${getBaseUrl()}/api/trpc`,/*** Set custom request headers on every request from tRPC* @link https://trpc.dokyumento.jp/docs/v10/header*/headers() {if (!ctx?.req?.headers) {return {};}// To use SSR properly, you need to forward client headers to the server// This is so you can pass through things like cookies when we're server-side renderingreturn {cookie: ctx.req.headers.cookie,};},}),],};},ssr(opts) {// only SSR if the request is coming from a botreturn opts.ctx?.req?.headers['user-agent']?.includes('bot');},});
utils/trpc.tstsx
import { httpBatchLink } from '@trpc/client';import { createTRPCNext } from '@trpc/next';import superjson from 'superjson';import type { AppRouter } from './api/trpc/[trpc]';export const trpc = createTRPCNext<AppRouter>({config(opts) {const { ctx } = opts;if (typeof window !== 'undefined') {// during client requestsreturn {links: [httpBatchLink({url: '/api/trpc',}),],};}return {links: [httpBatchLink({// The server needs to know your app's full urlurl: `${getBaseUrl()}/api/trpc`,/*** Set custom request headers on every request from tRPC* @link https://trpc.dokyumento.jp/docs/v10/header*/headers() {if (!ctx?.req?.headers) {return {};}// To use SSR properly, you need to forward client headers to the server// This is so you can pass through things like cookies when we're server-side renderingreturn {cookie: ctx.req.headers.cookie,};},}),],};},ssr(opts) {// only SSR if the request is coming from a botreturn opts.ctx?.req?.headers['user-agent']?.includes('bot');},});
pages/_app.tsxtsx
import { trpc } from '~/utils/trpc';import type { AppProps } from 'next/app';import React from 'react';const MyApp: AppType = ({ Component, pageProps }: AppProps) => {return <Component {...pageProps} />;};export default trpc.withTRPC(MyApp);
pages/_app.tsxtsx
import { trpc } from '~/utils/trpc';import type { AppProps } from 'next/app';import React from 'react';const MyApp: AppType = ({ Component, pageProps }: AppProps) => {return <Component {...pageProps} />;};export default trpc.withTRPC(MyApp);
よくある質問
Q: クライアントのヘッダーをサーバーに手動で転送する必要があるのはなぜですか? tRPC が自動的にそれを行わないのはなぜですか?
SSR を実行する際にクライアントのヘッダーをサーバーに転送したくないことはまれですが、ヘッダーに動的に何かを追加したい場合があります。そのため、tRPC はヘッダーキーの衝突などの責任を負いません。
Q: Node 18 で SSR を使用する場合、なぜ connection
ヘッダーを削除する必要があるのですか?
connection
ヘッダーを削除しないと、connection
は禁止されているヘッダー名であるため、データの取得は TRPCClientError: fetch failed
で失敗します。
Q: なぜネットワークタブでネットワークリクエストが fortfarande 行われているのが見えるのですか?
デフォルトでは、@tanstack/react-query
(データ取得フックに使用しています) は、SSR 経由で初期データがすでに取得されている場合でも、マウント時とウィンドウの再フォーカス時にデータを再取得します。これにより、データは常に最新の状態になります。この動作を無効にする場合は、SSG のページを参照してください.