伺服器端渲染
若要啟用 SSR,只需在 createTRPCNext
設定回呼中設定 ssr: true
。
資訊
為了在伺服器端渲染步驟中正確執行查詢,我們需要在 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.dev.org.tw/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.dev.org.tw/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.dev.org.tw/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.dev.org.tw/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);
常見問題
問:為什麼我需要手動將客戶端標頭轉發到伺服器?為什麼 tRPC 沒有自動為我執行此操作?
雖然在執行 SSR 時不轉發客戶端標頭到伺服器的情況很罕見,但你可能想在標頭中動態新增項目。因此,tRPC 不想承擔標頭金鑰衝突等責任。
問:為什麼我在 Node 18 上使用 SSR 時需要刪除 connection
標頭?
如果你不移除 connection
標頭,資料擷取會失敗並出現 TRPCClientError: 擷取失敗
,因為 connection
是 禁止的標頭名稱。
問:為什麼我仍然在網路標籤中看到發出的網路請求?
預設情況下,@tanstack/react-query
(我們用於資料擷取掛鉤)會在掛載和視窗重新聚焦時重新擷取資料,即使它已經透過 SSR 取得初始資料。這可確保資料始終是最新的。如果你想停用此行為,請參閱 SSG 頁面。