참고: Next.js 13부터 새로운 디렉토리인
app/
(베타)가 추가되었습니다. 이 새 디렉토리는 레이아웃, 중첩 라우트 및 기본적으로 서버 컴포넌트를 사용합니다.app/
안에서는 레이아웃 내에서 애플리케이션 전체의 데이터를 가져올 수 있으며, 더욱 세부적인 중첩 레이아웃(데이터 가져오기와 연결된)도 지원합니다.
app/
에 대해 자세히 알아보세요.
Next.js에서 페이지는 pages
디렉토리에 있는 .js
, .jsx
, .ts
또는 .tsx
파일에서 내보낸 React 컴포넌트입니다. 각 페이지는 파일 이름을 기반으로 한 경로(route)와 연결됩니다.
예시: pages/about.js
라는 파일을 만들고 아래와 같은 React 컴포넌트를 내보내면, /about
에서 접근 가능합니다.
export default function About() {
return <div>About</div>
}
Next.js는 동적 라우트를 가진 페이지를 지원합니다. 예를 들어, pages/posts/[id].js
라는 파일을 만들면 posts/1
, posts/2
등에서 접근 가능합니다.
동적 라우팅에 대해 자세히 알아보세요(Dynamic Routing).
기본적으로 Next.js는 모든 페이지를 프리 렌더링합니다. 이는 클라이언트 측 JavaScript가 모든 작업을 처리하는 대신 미리 각 페이지의 HTML
을 생성함으로써, 성능 및 검색 엔진 최적화(SEO) 측면에서 이점을 제공합니다.
각 생성된 HTML
은 해당 페이지에 필요한 최소한의 JavaScript 코드와 연결됩니다. 페이지가 브라우저에 의해 로드될 때, 해당 JavaScript 코드가 실행되어 페이지가 완전히 대화형으로 만들어집니다. (이 과정을 하이드레이션(hydration)이라고 합니다.)
Next.js에는 두 가지 프리 렌더링 형태가 있습니다: 정적 생성(Static Generation) 및 서버 사이드 렌더링(Server-side Rendering). 차이점은 페이지의 HTML
을 생성하는 시점입니다.
HTML
은 빌드 시간에 생성되며 각 요청에서 재사용됩니다.HTML
은 각 요청에서 생성됩니다.중요한 것은 Next.js에서는 각 페이지마다 어떤 프리 렌더링 형태를 사용할지 선택할 수 있다는 것입니다. 대부분의 페이지에 대해 정적 생성을 사용하고 일부 페이지에 대해서만 서버 사이드 렌더링을 사용하여 "하이브리드" Next.js 앱을 만들 수 있습니다.
성능 이유로 정적 생성을 서버 사이드 렌더링 대신 사용하는 것이 좋습니다. 정적 생성된 페이지는 CDN
에서 캐시될 수 있으므로 성능 향상을 위해 추가 구성이 필요하지 않습니다. 그러나 일부 경우에는 서버 사이드 렌더링이 유일한 옵션일 수 있습니다.
정적 생성 또는 서버 사이드 렌더링과 함께 클라이언트 측 데이터 가져오기도 사용할 수 있습니다. 이는 페이지의 일부를 클라이언트 측 JavaScript로 완전히 렌더링할 수 있음을 의미합니다. 자세한 내용은 데이터 가져오기(Data Fetching) 문서를 참조하세요.
정적 생성을 사용하는 경우, 페이지 HTML
은 빌드 시간에 생성됩니다. 이는 프로덕션 환경에서 next build
를 실행할 때 페이지 HTML
이 생성됩니다. 이 HTML
은 각 요청에서 재사용됩니다. CDN
에 의해 캐시될 수 있습니다.
Next.js에서 데이터가 있는지 없는지에 따라 정적 생성을 사용하여 페이지를 생성할 수 있습니다. 각각의 경우를 살펴보겠습니다.
기본적으로 Next.js는 데이터를 가져오지 않고 정적 생성을 사용하여 페이지를 프리 렌더링합니다.
예시:
function About() {
return <div>About</div>
}
export default About
이 페이지는 프리 렌더링을 위해 외부 데이터를 가져올 필요가 없습니다. 이와 같은 경우, Next.js는 각 페이지에 대해 빌드 시간에 단일 HTML
파일을 생성합니다.
일부 페이지는 프리 렌더링을 위해 외부 데이터를 가져와야 합니다. 두 가지 시나리오가 있으며, 각각 또는 모두에 적용할 수 있는 Next.js가 제공하는 함수가 있습니다.
getStaticProps
를 사용하세요.getStaticPaths
를 사용하세요 (대개 getStaticProps
와 함께 사용).예제: 블로그 페이지는 CMS(콘텐츠 관리 시스템)에서 블로그 글 목록을 가져와야 합니다.
// 이 페이지는 프리 렌더링을 위해 `posts`를 가져와야 합니다. (어떤 API 엔드포인트를 호출하는 등)
export default function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}
이 데이터를 프리 렌더링할 때, Next.js는 동일한 파일에서 getStaticProps
라는 async
함수를 익스포트하도록 허용합니다. 이 함수는 빌드 시간에 호출되며, 프리 렌더링 중에 페이지의 props
에 가져온 데이터를 전달할 수 있습니다.
export default function Blog({ posts }) {
// 글 목록을 렌더링합니다...
}
// 이 함수는 빌드 시간에 호출됩니다.
export async function getStaticProps() {
// API 엔드포인트를 호출하여 글 목록(posts)을 가져옵니다.
const res = await fetch('https://.../posts')
const posts = await res.json()
// `props: { posts }`를 반환함으로써, Blog 컴포넌트는 빌드 시간에 `posts`를 props로 받게 됩니다.
return {
props: {
posts,
},
}
}
Next.js는 동적 경로를 가진 페이지를 만들 수 있도록 허용합니다. 예를 들어, pages/posts/[id].js
라는 파일을 만들어 id
에 따라 단일 블로그 글을 보여줄 수 있습니다. 이렇게 하면 posts/1
에 액세스할 때 id: 1
인 블로그 글을 표시할 수 있습니다.
동적 라우팅에 대해 자세히 알아보려면 동적 라우팅(Dynamic Routing) 문서를 확인하세요.
그러나 어떤 id
를 프리 렌더링할 것인지는 외부 데이터에 따라 달라질 수 있습니다.
예제: 데이터베이스에 블로그 글(id: 1
) 하나만 추가한 경우, 빌드 시간에 posts/1
만 프리 렌더링하려고 할 수 있습니다.
나중에 두 번째 글(id: 2
)을 추가할 수 있습니다. 이 경우 두 번째 글인 posts/2
도 프리 렌더링하려고 할 것입니다.
즉, 프리 렌더링할 페이지 경로는 외부 데이터에 따라 달라집니다. 이 문제를 처리하려면 Next.js에서 동적 페이지(pages/posts/[id].js
이 경우)에서 getStaticPaths
라는 async
함수를 익스포트할 수 있습니다. 이 함수는 빌드 시간에 호출되며, 어떤 경로를 프리 렌더링할 것인지 지정할 수 있습니다.
// 이 함수는 빌드 시간에 호출됩니다.
export async function getStaticPaths() {
// API 엔드포인트를 호출하여 글 목록(posts)을 가져옵니다.
const res = await fetch('https://.../posts')
const posts = await res.json()
// posts를 기반으로 프리 렌더링할 경로를 가져옵니다.
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// 빌드 시간에 이 경로만 프리 렌더링합니다.
// { fallback: false }는 다른 경로는 404를 반환하도록 지정합니다.
return { paths, fallback: false }
}
또한 pages/posts/[id].js
에서는 getStaticProps
를 익스포트하여 이 id
에 대한 글 데이터를 가져와 프리 렌더링하는 데 사용할 수 있습니다.
export default function Post({ post }) {
// 글 데이터를 렌더링합니다...
}
export async function getStaticPaths() {
// ...
}
// 이 함수는 빌드 시간에도 호출됩니다.
export async function getStaticProps({ params }) {
// params에는 글 `id`가 포함됩니다.
// 루트가 /posts/1인 경우 params.id는 1입니다.
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// 글 데이터를 페이지로 전달합니다.
return { props: { post } }
}
getStaticPaths
가 작동하는 방식에 대해 자세히 알아보려면 데이터 가져오기(Data Fetching) 문서를 확인하세요.
언제 Static Generation
을 사용해야 할까요?
사용 가능한 경우 Static Generation
(데이터와 함께 또는 데이터 없이)을 사용하는 것이 좋습니다. 페이지를 한 번 빌드하고 CDN
에서 제공할 수 있기 때문에 서버에서 페이지를 매번 렌더링하는 것보다 훨씬 빠릅니다.
Static Generation
은 다음과 같은 종류의 페이지에 사용할 수 있습니다.
자문하자면 이 페이지를 사용자 요청보다 먼저 프리 렌더링할 수 있는지를 스스로에게 물어봐야 합니다. 가능하다면 Static Generation
을 선택해야 합니다.
반면, 페이지가 자주 업데이트되는 데이터를 표시하거나, 페이지 내용이 매번 요청마다 변경되는 경우 Static Generation
은 좋은 선택이 아닙니다.
이러한 경우 다음 중 하나를 수행할 수 있습니다.
Client-side data fetching
과 Static Generation
함께 사용: 페이지의 일부를 프리 렌더링하지 않고 클라이언트 측 JavaScript를 사용하여 채울 수 있습니다. 이 방법에 대해 자세히 알아보려면 데이터 가져오기(Data Fetching) 문서를 확인하세요.Server-Side Rendering
사용: Next.js는 매번 요청마다 페이지를 프리 렌더링합니다. CDN
에서 캐시할 수 없으므로 느리지만, 프리 렌더링된 페이지는 항상 최신 상태입니다. 이 방법에 대해 나중에 논의하겠습니다.SSR(Server-side Rendering) 또는 동적 렌더링이라고도 함.
페이지가 Server-side Rendering
을 사용하면, 페이지 HTML은 매번 요청마다 생성됩니다.
페이지를 Server-side Rendering
으로 사용하려면, getServerSideProps
라는 async
함수를 익스포트해야 합니다. 이 함수는 서버에서 매번 요청됩니다.
예를 들어, 페이지가 외부 API에서 가져온 자주 업데이트되는 데이터를 프리 렌더링해야 할 경우 getServerSideProps
를 작성하고 아래와 같이 데이터를 가져와 페이지의 props
로 전달할 수 있습니다.
export default function Page({ data }) {
// 데이터를 렌더링합니다...
}
// 이 함수는 모든 요청마다 호출됩니다.
export async function getServerSideProps() {
// 외부 API에서 데이터를 가져옵니다.
const res = await fetch(`https://.../data`)
const data = await res.json()
// 데이터를 페이지를 통해 props로 전달합니다.
return { props: { data } }
}
getServerSideProps
는 getStaticProps
와 유사하지만, getServerSideProps
는 빌드 시간이 아닌 매번 요청마다 실행된다는 점이 다릅니다.
getServerSideProps
가 작동하는 방식에 대해 자세히 알아보려면 데이터 가져오기(Data Fetching) 문서를 확인하세요.
Next.js에서 두 가지 유형의 프리 렌더링인 Static Generation
과 Server-side Rendering
에 대해 논의했습니다.
HTML
은 빌드 시점에 생성되며, 각 요청에서 재사용됩니다. 페이지에 정적 생성을 사용하려면 페이지 컴포넌트를 내보내거나, getStaticProps
(필요한 경우 getStaticPaths
도)를 내보내면 됩니다. 사용자 요청 전에 프리 렌더링할 수 있는 페이지에 적합합니다. 클라이언트 측 렌더링과 함께 사용하여 추가 데이터를 가져올 수도 있습니다.HTML
은 각 요청에서 생성됩니다. 서버 사이드 렌더링을 사용하려면 getServerSideProps
를 내보내면 됩니다. 정적 생성보다 성능이 느리기 때문에 절대적으로 필요한 경우에만 사용하세요.