Next.js 는 정적 사이트 생성(SSG)과 서버 사이드 렌더링(SSR) pre-rendering 웹사이트 생성을 도와주는 프레임워크라는 설명을 다른 글에서 소개했다.
Next.js에서는 SSG와 SSR을 위한 데이터 패칭 기능을 제공한다.
즉 사이트를 렌더링하기 전 어떤 데이터를 이용해서 페이지를 생성할 것인지에 대한 함수를 작성하는 기능을 말하는 것이다.
예를 들어 블로그 포스트에 대한 컴포넌트가 있다고 가정해보자.
function BlogPost() {
return (
<div>
<h1> title </h1>
<div> content </div>
</div>
)
}
위와 같이 포스트 컴포넌트는 제목
과 내용
이 필요하다.
그리고 블로그 포스트는 데이터베이스에 따로 저장해두었고, 아래와 같은 형식이라고 가정해보자.
https://.../posts
[
{
id: 1,
title: 'Next.js란?',
content: 'Next.js란 ...'
},
{
id: 2,
title: 'SSG와 SSR',
content: '정적 사이트 생성은 ...'
}
...
]
그리고 우리는 SSG를 통해 빌드 시 이 데이터를 BlogPost
컴포넌트에 전달해서 렌더링하고 싶다.
그럴 때 어떻게 해야할까?
이럴 때 사용할 수 있는 Next.js의 기본 함수가 바로 getStaticProps
이다.
static
에서 정적 사이트 생성, props
에서 컴포넌트의 인풋과 연관이 있다는 점을 눈치챘을 것이다.
getStaticProps
는 빌드 시 데이터를 패치하는 함수이다.
Next.js 코드에 getStaticProps
가 있다면 Next.js가 빌드시 알아서 함수를 실행하고, 그 props를 컴포넌트에 전달한다.
기본틀은 아래와 같이 생겼다.
export async function getStaticProps(context) {
return {
props: {},
}
}
위에서 들었던 블로그 포스트 예제로 돌아가서 내가 id값이 1인 Next.js란?
블로그 포스팅을 렌더링하고 싶다면 아래와 같이 코드를 작성할 수 있다.
function BlogPost({ post }) {
return (
<div>
<h1> {post.title} </h1>
<div> {post.content} </div>
</div>
)
}
export async function getStaticProps() {
const res = await fetch('https://.../posts/1')
const post = await res.json()
return {
props: {
post,
}
}
}
export default BlogPost
getStaticProps
에서 데이터베이스로부터 id 값이 1인 해당 포스트 데이터를 불러오고, 그 post
데이터를 props로 리턴한다. 그러면 컴포넌트가 props를 통해 렌더링을 할 수 있는 것이다.
이 쯤 되면 이런 의문도 생길 수 있다.
만약 블로그 포스팅이 100개가 있다면, 이런 경우에는 경로를 어떻게 설정해야될까? 매 포스팅마다 pages/
폴더 아래 자바스크립트 파일을 만들어줘야할까?
당연히 아니다. Next.js에는 동적 라우팅(dynamic routes) 기능이 있고, getStaticPaths
를 사용해 렌더링하기 위해 필요한 경로를 설정할 수 있다.
(동적 라우팅에 대한 설명은 다른 글에서 자세히 다루겠습니다)
getStaticPaths
는 데이터에 따라 pre-rendering할 페이지의 동적 경로를 지정하는 함수이다.
기본틀은 아래와 같다.
export async function getStaticPaths() {
return {
paths: [
{ params: { ... } }
],
fallback: ...
};
}
그리고 getStaticPaths
는 paths
를 getStaticProps
로 리턴한다.
블로그 포스팅 예제로 돌아오자면, 각 포스팅을 위해
/pages/posts/1.js
/pages/posts/2.js
...
/pages/posts/100.js
각각 파일을 생성할 필요 없이, /pages/posts/[id].js
파일 하나만으로도 모든 페이지를 생성할 수 있다는 뜻이다.
function BlogPost({ post }) {
return (
<div>
<h1> {post.title} </h1>
<div> {post.content} </div>
</div>
)
}
export async function getStaticPaths() {
const res = await fetch('http://.../posts')
const posts = await res.json()
const paths = posts.map((post) => ({
params: { id: post.id },
}))
return { paths, fallback: false }
}
export async function getStaticProps({ params }) {
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
return {
props: {
post,
}
}
}
export default BlogPost
getStaticPaths
에서 /posts
에 저장된 모든 블로그 포스팅 데이터를 불러오고, id 값을 파라미터로 리턴한다.
그러면 getStaticProps
에서는 각 path
의 params
값을 받아 id를 통해 블로그 포스트를 불러오고, 그 post
를 props
로 컴포넌트에 전달한다.
한 눈에 정리하자면 이렇다.
그리고 fallback
에 대한 부분은 paths에서 리턴되지 않은 경로에 대해서 어떻게 처리할지를 정하는 것인데, 우선은 아래의 내용만 알고 넘어가도 무관하다.
false
: 404 를 전달하겠다.true
: 404를 전달하지 않고, "fallback" 버전의 페이지를 첫 request에서 보여준 후, 페이지가 생성되고 나면 그 이후의 request부터는 생성된 페이지를 보여주겠다.blocking
: 서버 사이드 렌더링을 통해 HTML이 생성되기 까지 기다리겠다.마지막으로 getServerSideProps
는 getStaticProps
와 비슷하지만 서버 사이드 렌더링을 위한 함수이다.
getStaticProps
처럼 컴포넌트에 props를 넘겨준다는 공통점이 있지만, 빌드 시가 아닌 매 request마다 실행된다는 차이점이 있다.
getServerSideProps
는 매 request마다 데이터를 패치하는 함수이다.
export async function getServerSideProps(context) {
return {
props: {},
}
}
또 하나 getStaticProps
와 다른 점은, 'req' 미들웨어가 제공된다. (client로 부터 request를 받을 때 마다 실행되므로)
getStaticProps
와 getStaticPaths
는 정적 사이트 생성을 위해 사용된다.getServerSideProps
는 서버 사이드 렌더링을 위해 사용된다.getStaticProps
와 getServerSideProps
는 데이터를 패치하는 함수이다.getStaticPaths
는 페이지의 동적 경로를 지정하는 함수이다.
덕분에 도움이 되었습니다. 감사합니다