본문 바로가기
버전: 11.x

정적 사이트 생성

비공식 베타 번역

이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →

정적 사이트 생성은 각 페이지의 getStaticProps 내부에서 tRPC 쿼리를 실행해야 합니다.

서버 사이드 헬퍼를 사용하여 쿼리를 미리 가져오고, dehydrate한 다음 페이지로 전달하면 됩니다. 그러면 쿼리가 자동으로 trpcState를 가져와 초기값으로 사용합니다.

getStaticProps에서 데이터 가져오기

pages/posts/[id].tsx
tsx
import { createServerSideHelpers } from '@trpc/react-query/server';
import { prisma } from '~/server/context';
import { appRouter } from '~/server/routers/_app';
import { trpc } from '~/utils/trpc';
import {
GetStaticPaths,
GetStaticPropsContext,
InferGetStaticPropsType,
} from 'next';
import superjson from 'superjson';
export async function getStaticProps(
context: GetStaticPropsContext<{ id: string }>,
) {
const helpers = createServerSideHelpers({
router: appRouter,
ctx: {},
transformer: superjson, // optional - adds superjson serialization
});
const id = context.params?.id as string;
// prefetch `post.byId`
await helpers.post.byId.prefetch({ id });
return {
props: {
trpcState: helpers.dehydrate(),
id,
},
revalidate: 1,
};
}
export const getStaticPaths: GetStaticPaths = async () => {
const posts = await prisma.post.findMany({
select: {
id: true,
},
});
return {
paths: posts.map((post) => ({
params: {
id: post.id,
},
})),
// https://nextjs.org/docs/pages/api-reference/functions/get-static-paths#fallback-blocking
fallback: 'blocking',
};
};
export default function PostViewPage(
props: InferGetStaticPropsType<typeof getStaticProps>,
) {
const { id } = props;
const postQuery = trpc.post.byId.useQuery({ id });
if (postQuery.status !== 'success') {
// won't happen since we're using `fallback: "blocking"`
return <>Loading...</>;
}
const { data } = postQuery;
return (
<>
<h1>{data.title}</h1>
<em>Created {data.createdAt.toLocaleDateString('en-us')}</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 { prisma } from '~/server/context';
import { appRouter } from '~/server/routers/_app';
import { trpc } from '~/utils/trpc';
import {
GetStaticPaths,
GetStaticPropsContext,
InferGetStaticPropsType,
} from 'next';
import superjson from 'superjson';
export async function getStaticProps(
context: GetStaticPropsContext<{ id: string }>,
) {
const helpers = createServerSideHelpers({
router: appRouter,
ctx: {},
transformer: superjson, // optional - adds superjson serialization
});
const id = context.params?.id as string;
// prefetch `post.byId`
await helpers.post.byId.prefetch({ id });
return {
props: {
trpcState: helpers.dehydrate(),
id,
},
revalidate: 1,
};
}
export const getStaticPaths: GetStaticPaths = async () => {
const posts = await prisma.post.findMany({
select: {
id: true,
},
});
return {
paths: posts.map((post) => ({
params: {
id: post.id,
},
})),
// https://nextjs.org/docs/pages/api-reference/functions/get-static-paths#fallback-blocking
fallback: 'blocking',
};
};
export default function PostViewPage(
props: InferGetStaticPropsType<typeof getStaticProps>,
) {
const { id } = props;
const postQuery = trpc.post.byId.useQuery({ id });
if (postQuery.status !== 'success') {
// won't happen since we're using `fallback: "blocking"`
return <>Loading...</>;
}
const { data } = postQuery;
return (
<>
<h1>{data.title}</h1>
<em>Created {data.createdAt.toLocaleDateString('en-us')}</em>
<p>{data.text}</p>
<h2>Raw data:</h2>
<pre>{JSON.stringify(data, null, 4)}</pre>
</>
);
}

react-query의 기본 동작은 마운트 시 클라이언트 사이드에서 데이터를 다시 가져오는 것이므로, getStaticProps를 통해서만 데이터를 가져오고 싶다면 쿼리 옵션에서 refetchOnMountrefetchOnWindowFocusfalse로 설정해야 합니다.

이는 API 요청 수를 최소화하고 싶을 때 유용하며, 예를 들어 요청량이 제한된 서드파티 API를 사용하는 경우 필요할 수 있습니다.

쿼리별로 설정할 수 있습니다:

tsx
const data = trpc.example.useQuery(
// if your query takes no input, make sure that you don't
// accidentally pass the query options as the first argument
undefined,
{ refetchOnMount: false, refetchOnWindowFocus: false },
);
tsx
const data = trpc.example.useQuery(
// if your query takes no input, make sure that you don't
// accidentally pass the query options as the first argument
undefined,
{ refetchOnMount: false, refetchOnWindowFocus: false },
);

애플리케이션 전체의 모든 쿼리가 동일하게 동작해야 한다면 전역적으로 설정할 수도 있습니다:

utils/trpc.ts
tsx
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(config) {
return {
links: [
httpBatchLink({
url: `${getBaseUrl()}/api/trpc`,
}),
],
// Change options globally
queryClientConfig: {
defaultOptions: {
queries: {
refetchOnMount: false,
refetchOnWindowFocus: false,
},
},
},
},
},
});
utils/trpc.ts
tsx
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(config) {
return {
links: [
httpBatchLink({
url: `${getBaseUrl()}/api/trpc`,
}),
],
// Change options globally
queryClientConfig: {
defaultOptions: {
queries: {
refetchOnMount: false,
refetchOnWindowFocus: false,
},
},
},
},
},
});

애플리케이션에 정적 쿼리와 동적 쿼리가 혼합되어 있다면 이 방식 사용 시 주의가 필요합니다.