Next.js

[Next.js] Data Fetching (getStaticProps/getStaticPaths/getServerSideProps)

킹우현 2023. 8. 12. 16:52

Next.js 는 정적 사이트 생성(SSG)과 서버 사이드 렌더링(SSR) pre-rendering 웹사이트 생성을 도와주는 프레임워크이다.

 

Next.js에서는 SSG와 SSR을 위한 데이터 패칭 기능을 제공한다. 즉, 사이트를 렌더링하기 전 어떤 데이터를 이용해서 페이지를 생성할 것인지에 대한 함수를 작성하는 기능을 말하는 것이다. ( getStaticPropsgetStaticPaths, getServerSideProps )

getStaticProps

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// SSG
export async function getStaticProps(context) {
  // 외부 API 호출
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },
  }
}

export default Blog

getStaticProps빌드 시 데이터를 Fetch하는 함수이다. 정적 페이지 생성(Static Site Generation) 방식으로 CSR이 아니고, 항상 서버에서 실행된다.

 

사전 렌더링시 데이터를 가져오려면, 같은 파일 내에서 getStaticProps라는 비동기(async) 함수를 export해야 한다.


이 함수는 빌드시 호출되어, 페이지가 사전 렌더링될 때 데이터를 가져와 페이지의 props로 데이터를 전달할 수 있게 한다.


빌드 단계에서만 데이터를 가져오고 JSON으로 저장하여 고정적으로 사용한다. 가져온 데이터를 props에 담고 return하여 컴포넌트에 전달한다. 페이지 요청 때마다 데이터를 가져오는 게 아니라서 성능 면에서 뛰어나다. ⭐️

 

👉🏻 빌드 후에도 고정되는 내용을 보여주는 페이지에 적합하다.
(ex. 블로그 포스트, 상품 페이지, Docs 등 내용이 고정적이며 SEO가 중요한 페이지)

 

getStaticProps()는 매개변수로 context를 가질 수도 있는데, 만약 페이지가 pages/posts/[postId]로 동적 라우팅이 되어있는 경우 params 속성을 이용해 파라미터를 얻을 수 있다.

✨ getStaticProps의 매개변수인 context의 객체 구성
- params: 동적 경로를 사용하는 페이지에 대한 정보를 담는다. 동적 페이지의 파일명이 [id].js인 경우 context.params는 {id: ...}를 반환한다.
- req: HTTP request object
- res: HTTP response object
- query: 쿼리 문자열
- preview: preview mode 여부
- previewData: setPreviewData로 설정된 데이터
✨ getStaticProps의 반환값
- props(option) : 해당 컴포넌트로 반환할 값
- revalidate(option) : 해당 페이지의 재생성 발생 가능 시간(sec). 기본 값은 false다. false일 경우 해당 페이지가 다음 빌드 때까지 빌드된 상태로 캐시된다.
- notFound(option) : Boolean 값, 404 에러를 반환한다.

getStaticPaths

// 아래의 getStaticPaths는 빌드시 호출된다.
export async function getStaticPaths() {
  const res = await fetch('https://.../posts'); // API 엔드포인트를 이용해 posts를 가져온다.
  const posts = await res.json();
 
  // 데이터(posts)에서 우리가 사전 렌더링하고 싶은 path를 추출한다.
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }));
 
  // 빌드시 여기서 전달한 경로들만 사전 렌더링된다.
  // { fallback: false }은 다른 경로는 404에러로 처리된다는 뜻이다.
  return { paths, fallback: false };
}

getStaticPaths데이터에 따라 pre-rendering할 페이지의 동적 경로를 지정하는 함수이다. Next.js에는 동적 라우팅(dynamic routes) 기능이 있고, getStaticPaths를 사용해 렌더링하기 위해 필요한 경로를 설정할 수 있다.

 

사전 렌더링되는 페이지의 경로가 외부 데이터에 의존한다면, 해당 동적인 페이지에서 getStaticPaths()라는 비동기 함수를 export하면 된다.

 

이 함수는 빌드시 호출되어 사전 렌더링할 경로(path)를 지정할 수 있다.

 

동적 경로를 사용하는 페이지에서 getStaticPaths라는 함수를 사용할 때 Next.js는 getStaticPaths에 지정된 모든 경로를 정적으로 미리 렌더링한다.

 

export default function Post({ post }) {
  // ...
}
 
export async function getStaticPaths() {
  // ...
}
 
// id를 이용해 해당 id를 가진 블로그 포스트의 데이터를 가져온다.
export async function getStaticProps({ params }) {
  const res = await fetch(`https://.../posts/${params.id}`);
  const post = await res.json();
 
  return { props: { post } };
}

그리고 getStaticPaths는 paths를 getStaticProps 로 리턴하고 params를 통해 경로별로 데이터를 가져와 사전 렌더링을 할 수 있다.

 

fallback은 paths에서 리턴되지 않은 경로에 대해서 어떻게 처리할지를 정하는 것이다.

✨ 매개변수 fallback 값 종류
- false : 404 를 전달하겠다.
- true : 404를 전달하지 않고, "fallback" 버전의 페이지를 첫 request에서 보여준 후, 페이지가 생성되고 나면 그 이후의 request부터는 생성된 페이지를 보여주겠다.
- blocking : 서버 사이드 렌더링을 통해 HTML이 생성되기 까지 기다리겠다.

예제

블로그 포스팅을 예제로 돌자면, 각 포스팅을 위해
/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로 컴포넌트에 전달한다.

 

getStaticProps와 getStaticPaths

1. 페이지의 콘텐츠가 외부 데이터에 의존한다면, getStaticProps()를 사용한다.
2. 페이지의 경로가 외부 데이터에 의존한다면, getStaticPaths()를 사용한다. (주로 getStaticProps()와 함께 사용한다.)

getServerSideProps

export default function Page({ data }) { // 데이터를 props로 받는다.
  // ...
}
 
// 아래의 getServerSideProps 함수는 매 요청(request)마다 호출된다.
export async function getServerSideProps() {
  const res = await fetch(`https://.../data`); // 외부 API로부터 데이터를 가져온다.
  const data = await res.json();

  return { props: { data } }; // 데이터를 props로 전달한다.
}

getServerSideProps매 요청(request)마다 데이터를 패치하는 함수이다. 이 함수는 서버 사이드 렌더링(SSR) 방식으로, 서버 측에서만 실행되고 브라우저에서는 실행되지 않는다.

 

만약, 외부 API에서 가져오는 자주 업데이트되는 데이터를 가진 페이지를 사전 렌더링해야 한다면, getServerSideProps()를 이용해 데이터를 가져와서 페이지에 전달할 수 있다.

 

getServerSidePropsgetStaticProps 처럼 컴포넌트에 props를 넘겨준다는 공통점이 있지만, 빌드 시가 아닌 매 요청(Request)마다 실행된다는 차이점이 있다.

 

또 하나 getStaticProps 와 다른 점은, 'req' 미들웨어가 제공된다. (client로 부터 request를 받을 때 마다 실행되므로)


외부 데이터를 서버에서 받아와 초기 데이터로 설정하고 페이지로 전달하며, 페이지 요청 시마다 실행된다.getStaticProps보다 성능이 떨어지지만, 동적으로 데이터를 가져와 업데이트가 가능하다는 장점이 있다. (Dynamic Rendering)

 

가져온 데이터를 props에 담고 return하여 컴포넌트에 전달한다.

 

👉🏻 요청 시 데이터를 가져와야 하는 페이지를 미리 렌더링해야 하는 경우에만 사용한다.

(ex. 외부 API 활용해 데이터를 동적으로 가져오는 경우 등)

 

🚨 Next.js는 getServerSideProps를 정말 필요할 때만 사용하라고 권고한다. (CDN에 캐싱되지 않아 느리기 때문)

또한, 데이터를 미리 가져올 필요가 없다면 클라이언트 측에서 데이터를 가져오는 것도 고려해봐야 한다.
(ex. 사용자 대시보드는 사용자별 비공개 페이지이므로 SEO와 관련 없으며 미리 렌더링할 필요가 없다.)

 

또한, getServerSideProps()는 매개변수로 context 객체를 전달받아 요청 객체 / 응답 객체에 접근할 수도 있다.

export async function getServerSideProps(context) {
  const req = context.req; // 요청 객체 - 인증(authentication)이 필요한 경우
  const res = context.res; // 응답 객체
  
  //...
  return { props: { data } };
}
✨ getServerSideProps의 매개변수인 context의 객체 구성
- params: 동적 경로를 사용하는 페이지에 대한 정보를 담는다. 동적 페이지의 파일명이 [id].js인 경우 context.params는 {id: ...}를 반환한다.
- req: HTTP request object
- res: HTTP response object
- query: 쿼리 문자열
- preview: preview mode 여부
- previewData: setPreviewData로 설정된 데이터
✨ getServerSideProps의 반환값
- props(option) : 해당 컴포넌트로 반환할 값
- redirect(option) : 값 내부와 외부 리소스 리디렉션 허용한다.{ destination: string, permanent: boolean }
- notFound(option) : Boolean 값, 404 에러를 반환한다.

 

정리

  • getStaticProps와 getStaticPaths는 정적 사이트 생성을 위해 사용된다.
  • getServerSideProps는 서버 사이드 렌더링을 위해 사용된다.
  • getStaticProps와 getServerSideProps는 데이터를 패치하는 함수이다.
  • getStaticPaths는 페이지의 동적 경로를 지정하는 함수이다.