상세 컨텐츠

본문 제목

[Next.js] 3.Data Fetching (데이터 가져오기) - getStaticProps

NextJS

by hong_2 2021. 8. 27. 16:23

본문

Data Fetching

이전 포스트에서 정적 생성(Static Generation)과 서버 사이드 렌더링(Server-Side Renderin)을 알아보았다.

이번 포스트에서는 데이터를 가져오기 위해 Next.js에서 제공하는 세 가지 함수 및 client-side에서 어떻게 데이터를 가져오는지 알아보자.

 

Next.js에서는 데이터를 가져오기위해 세 가지 함수가 사용된다:

  • getStaticProps (Static Generation) : 프로젝트가 빌드될 때 데이터를 가져온다.
  • getStaticPaths (Static Generation) :  데이터를 기반으로 동적 라우트를 지정한다.
  • getServerSideProps (Server-Side Rendering) : 각 요청이 있을 때마다 데이터를 가져온다.

 

getStaticProps (Static Generation)

getStaticPropsasync 함수를 통해 내보내기(export)를 하게 되면 Next.jsgetStaticProps 함수에서 반환된 속성 값을 이용하여 사전 렌더링을 하게 된다.

export async function getStaticProps(context) {
  return {
    props: {}, // will be passed to the page component as props
  }
}

`context ` 파라미터는 다음의 키값들을 포함한 객체이다.

  • params :  `params`는 동적 라우팅이 사용된 페이지의 route 파라미터들이 포함되어 있다.  예를 들면 , 페이지의 이름이 `[id].js`이면 `params`는 `{id :... }`과 같이 객체의 형태를 가진다. route 파라미터를 활용하기 위해서는 `getStaticPaths` 함수를 사용하여야 한다.
  • preview :  미리보기 모드가 설정되어 있으면 `true` 값을 가지고 아닌 경우 `undefined`값을 가진다. preview 모드는 추후에 다루도록 하겠다.
  • previewData : `setPreviewData`에 의해 설정된 미리보기 데이터가 포함되어 있다.
  • locale :  현재 설정된 locale (사용자의 인터페이스에서 사용되는 언어, 지역 설정, 출력 형식, 날짜 시간 등을 정의하는 문자열)이 포함되어 있다.
  • locales :  지원가능 한 모든 locale들이 포함되어 있다.
  • defaultLocale :  설정된 기본 locale이 포함되어 있다.

 

`getStaticProps`는 다음 객체를 반환해야 한다.

  • props : 페이지 컴포넌트에서 받은 속성 값 가진 객체 (선택)
  • revailidate :  페이지 재생성이 발생할 수 있는 초 (선택)
  • notFound : 404 상태와 페이지를 리턴할지 결정하는 boolean 값 (선택)
  • redirect : 리다이렉트 값이 들어 있는 객체 (선택), `redirect`는 `{ destination : string , permanent: boolean }` 형태의 객체이다
export async function getStaticProps(context) {
  const res = await fetch(`https://...`)
  const data = await res.json()

  if (!data) {
    return {
      redirect: {
        destination: '/',
        permanent: false,
      },
    }
  }

  return {
    props: { data }, // will be passed to the page component as props
  }
}

 

When should I use `getStaticProps`?

`getStaticProps`를 사용해야할 때:

  • 페이지를 렌더하기 위한 데이터가 빌드 간에 사용자의 요청에 보다 먼저 사용 가능할 때
  • headless CMS로 부터 전달받은 데이터를 사용할 때
    - headless CMS(headless Content Management System) : 보통 데이터를 전송 받을때 헤드에는 데이터를 보여줄 방법,수단을 명시하고 바디에는 컨텐츠를 담는다. 즉 headless는 단어 뜻 그대로 데이터를 보여줄 방벙을 제외한 순수 데이터만 오는 컨텐츠 관리 시스템을 말한다.
  • 유저단위가 아닌 공통으로 캐시가 될수 있는 데이터를 사용할 때
  • 페이지가 SEO(Search Engine Optimaztion - 검색 엔진 최적화)를 위해 사전 렌더링 되거나 빠른 로딩을 원할때
    - 지속적으로 언급하지만 `getStaticProps` 로 생성된 HTML 파일과 JSON파일은 효율성을 위해  CDN에 캐시된다.

Incremental Static Regeneration (증분 정적 재생성)

Next.js 는 사이트를 빌드 한 후 정적 페이지를 만들거나 업데이트가 가능하다. 증분 정적 재생성(ISR)은 페이지 단위를 기반으로하여 전체 사이트를 다시 빌드하지 않고 정적 생성을 사용할 수 있게 해준다.

증분 정적 재생성은 `revalidate` 속성을 통해 사용이 가능하다.

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

// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// revalidation is enabled and a new request comes in
export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },
    // Next.js will attempt to re-generate the page:
    // - When a request comes in
    // - At most once every 10 seconds
    revalidate: 10, // In seconds
  }
}

// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// the path has not been generated.
export async function getStaticPaths() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Get the paths we want to pre-render based on posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // We'll pre-render only these paths at build time.
  // { fallback: blocking } will server-render pages
  // on-demand if the path doesn't exist.
  return { paths, fallback: 'blocking' }
}

export default Blog

이미 렌더링된 페이지에서 요청이 발생하게 되면, 최초로 캐시가 된 페이지를 보여주게 된다.

  • 최초 요청과 10초가 지나지 않은 요청 뒤에 오는 요청은 캐시가 되며 동시성을 갖는다.
  • 10초가 지난 후, 다음 요청은 캐시가 된 페이지를 보여준다.
  • Next.js가 백그라운드에서 페이지 재생성을 한다.
  • 페이지가 성공적으로 생성되면, Next.js는 캐시를 무효화 하고 새로 업데이트 된 페이지를 보여준다. 만약 백그라운드 재생성이 실패하게 되면, 과거 페이지를 변경없이 보여준다.

Reading files: Use `process.cwd()`

`getStaticProps` 의 파일시스템을 통해 파일을 바로 읽어드릴수 있다.

파일을 읽어들이기 위해서는 절대 경로를 알고 있어야한다.

Next.js는 코드를 각기 분리된 디렉토리에서 컴파일하기 때문에 상대경로를 반환하는 `__dirname`을 사용할 수 없다.

대신에 `process.cwd()`를 통해 이를 해결할 수 있다.

import { promises as fs } from 'fs'
import path from 'path'

// posts will be populated at build time by getStaticProps()
function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>
          <h3>{post.filename}</h3>
          <p>{post.content}</p>
        </li>
      ))}
    </ul>
  )
}

// This function gets called at build time on server-side.
// It won't be called on client-side, so you can even do
// direct database queries. See the "Technical details" section.
export async function getStaticProps() {
  const postsDirectory = path.join(process.cwd(), 'posts')
  const filenames = await fs.readdir(postsDirectory)

  const posts = filenames.map(async (filename) => {
    const filePath = path.join(postsDirectory, filename)
    const fileContents = await fs.readFile(filePath, 'utf8')

    // Generally you would parse/transform the contents
    // For example you can transform markdown to HTML here

    return {
      filename,
      content: fileContents,
    }
  })
  // By returning { props: { posts } }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      posts: await Promise.all(posts),
    },
  }
}

export default Blog

 

Technical details(기술 상세)

 

Only runs at build time 

`getStaticProps`는 빌드가 진행될 때에만 실행할수 있기 때문에 , query parameters나 정적 HTML을 생성하는 HTTP Headers와 같이 요청 시간에만 유효한 데이터는 받을 수가 없다.

 

Write server-side code directly 

`getStaticProps`는 오직 서버 사이드에서만 실행된다. 클라이언트 사이드에서는 실행되지 않는다. 또한 브라우저를 위한 JS번들에도 포함되지 않는다. 즉, 직접 데이터베이스 쿼리와 같은 코드를 브라우저에 보내지 않고도 작성할 수 있다.

`getStaticProps`에서 API route를 호출하지 않고 함수 내에서 서버 사이드 코드를 직접 작성 해야한다.

 

Statically Generates both HTML and JSON

`getStaticProps`가 있는 페이지가 빌드간에 미리 렌더링되면 페이지의 HTML 파일 뿐만 아니라 `getStaticProps`의 실행 결과가 포함된 JSON 파일도 같이 생성된다.

 

이 JSON파일은 `next/link` 또는 `next/router`와 같은  클라이언트 사이드 라우팅에 사용된다. 만약 우리가 `getStaticProps`를 통해 사전에 렌더링된 페이지를 탐색하게 되면, Next.js는 빌드시에 생성된 이 JSON파일을 가져와서 컴포넌트의 속성으로 사용하게된다. 즉, 클라이언트 사이드 페이지의 전환이 `getStaticProps`를 호출하는게 아니라 단순하게 내보내진 JSON 파일만 사용되는 것이다.

Only allowed in a page

`getStaticProps` 함수는 오직 페이지에서만 내보내기가 가능하다. 이러한 제한의 이유는 리액트가 페이지가 렌더되기전에 필요로하는 모든 데이터를 가져야하기 때문이다. 또한 반드시 `export async function getStaticprops{}`를 써야한다. - 단순히 페이지 컴포넌의 속성으로 `getStaticProps`를 사용하게 되면 작동하지 않는다.

 

Runs on every request in development

`next dev`와 같이 개발 모드에서는 모든 요청에 대해 `getStaticProps`를 호출한다.

 

Preview Mode

몇몇 경우에는 우리는 일시적으로 정적 생성을 피해 빌드시간이 아닌 요청 시간에 페이지를 렌더하고 싶을 때가 있다.

예를 들면 headless CMS 를 사용하고있고 대략적인 퍼블리싱을  미리 보기하고 싶은 경우이다. 이 경우에는 Next.js가 Preview Mode를 지원한다.

 

 

 

지금까지 data fecthing 함수중 getStaticProps에 대해 알아봤다. 다음편에서는 getStaticPaths에 대해 알아보자.

 

 

참고자료

https://nextjs.org/docs/basic-features/data-fetching

관련글 더보기

댓글 영역