NEXT.js 알아보기 - Data Fetching

데브현·2023년 9월 19일
1

NEXT.js를 알아보자

목록 보기
2/3

이번에는 Next.js에서 설명하는 Data Fetching을 주제로 작성해보려 한다.
Data fetching에 따라 Next.js는 서로 다른 랜더링을 제공한다.

getStaticProps

getStaticProps함수를 페이지에서 사용하면 이 페이지는 Static Site Generation으로 렌더링 한다. 이는 빌드 타임에 props를 사용해 렌더링하게 된다.

import type { InferGetStaticPropsType, GetStaticProps } from 'next'
 
type Repo = {
  name: string
  stargazers_count: number
}
 
export const getStaticProps = (async (context) => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo = await res.json()
  return { props: { repo } }
}) satisfies GetStaticProps<{
  repo: Repo
}>
 
export default function Page({
  repo,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  return repo.stargazers_count
}

pre-rendering되는 방식과 관계없이 페이지 컴포넌트들에 어떠한 props든 통과되며, client-side HTML에서는 볼 수 있다. 그렇기에 민감한 정보는 props로 전달하면 안된다.

언제 사용해야 하는가?

  • 페이지 랜더링에 필요한 데이터가 유저의 요청전에 빌드 타임에서 사용이 가능할 때
  • 데이터가 headless CMS에서 올때
  • 페이지가 반드시 pre-render되야 하고 빨라야 할때
  • 데이터를 공개적으로 캐시할 때

언제 실행되는가?

getStaticProps는 항상 서버에서 실행되며 클라이언트에서는 실행되지 않는다.

  • next build 명령어를 실행 중에 항상 실행된다.
  • fallback: true 옵션을 사용하면 background에서 실행된다.
  • fallback: blocking 옵션을 사용하면 초기 랜더링 전에 실행된다.
  • revalidate 옵션을 사용하면 background에서 실행된다.
  • revalidate() 옵션을 사용하면 background에서 요청이 올때 실행된다.

Server-side 코드 직접 작성하기

getStaticProps는 서버에서만 실행되기 때문에 브라우저를 위한 js bundle에 포함되지 않는다. 그래서 db queries에 직접적으로 접근할 수 있다. getStaticProps 내에서 직접 서버사이드 코드를 작성할 수 있다.

// lib/load-posts.js
// The following function is shared
// with getStaticProps and API routes
// from a `lib/` directory
export async function loadPosts() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts/')
  const data = await res.json()
 
  return data
}
// pages/blog.js
import { loadPosts } from '../lib/load-posts'
 
// This function runs only on the server side
export async function getStaticProps() {
  // Instead of fetching your `/api` route you can call the same
  // function directly in `getStaticProps`
  const posts = await loadPosts()
 
  // Props returned will be passed to the page component
  return { props: { posts } }
}

HTML과 JSON을 같이 정적으로 생성하기

getStaticProps는 빌드시 pre-rendering되면 HTML 파일 이외에도 json파일을 생성한다.
json파일은 클라이언트 측에서 routing시(next/link, next/router)에 사용된다. 페이지 에서는 props를 위해 이 json을 fetch하게 된다. 이는 클라이언트 측 페이지의 전환이 다시 getStaticProps를 부르는 것이 아닌 한번 export된 json을 사용한다.

어디에서 사용할 수 있나?

getStaticProps는 페이지에서만 export할 수 있다. 페이지가 아닌 파일들(_app,_document,_error)에서는 사용이 불가능하다.
그 이유는 react는 페이지가 렌더링 되기 전에 데이터가 필요하기 때문이다.

getStaticPaths

페이지들이 동적인 router를 가지고 있고 getStaticProps를 사용한다면 정적으로 생성될 path들의 리스트 정의가 필요할 것이다.

getStaticPaths에 정의된 내용에 따라 정적으로 pre-rendering을 진행할 것이다.

import type {
  InferGetStaticPropsType,
  GetStaticProps,
  GetStaticPaths,
} from 'next'
 
type Repo = {
  name: string
  stargazers_count: number
}
 
export const getStaticPaths = (async () => {
  return {
    paths: [
      {
        params: {
          name: 'next.js',
        },
      }, // See the "paths" section below
    ],
    fallback: true, // false or "blocking"
  }
}) satisfies GetStaticPaths
 
export const getStaticProps = (async (context) => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo = await res.json()
  return { props: { repo } }
}) satisfies GetStaticProps<{
  repo: Repo
}>
 
export default function Page({
  repo,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  return repo.stargazers_count
}

언제 사용해야 하는가?

동적인 routes를 사용할 때와 더블어 아래와 같은 상황일떄 getStaticPaths를 사용해야 한다.

  • headless CMS로 부터 데이터가 올 때
  • db에서 데이터를 받아올 때
  • filesystem에서 데이터를 받아올 때
  • 데이터를 공개적으로 캐시할 때
  • 데이터가 반드시 pre-render되야 하고 빨라야 할 때

언제 실행되는가?

getStaticPaths는 production빌드일때만 실행되고 런타임에서는 실행되지 않는다.

getStaticPaths에 따른 getStaticProps 실행 방식

  • next build 후 반환된 모든 paths 항목에 대해 실행된다.
  • fallback: true옵션을 사용할 때 background에서 실행된다.
  • fallback: blocking옵션을 사용할 때 초기 랜더링 전에 실행된다.

어디에서 사용할 수 있나?

  • getStaticPaths는 반드시 getStaticProps와 함께 쓰여야 한다.
  • getServerSideProps와 같이 사용할 수 없다.
  • 페이지가 아닌 파일에서는 사용할 수 없다.
  • getStaticPaths는 페이지 구성 요소의 속성이 아닌 독립 실행형 함수로 내보내야 한다.

getServerSideProps

getServerSideProps를 사용하면 Server-side Rendering으로 인식해 매요청마다 pre-rendering을 진행한다.

import type { InferGetServerSidePropsType, GetServerSideProps } from 'next'
 
type Repo = {
  name: string
  stargazers_count: number
}
 
export const getServerSideProps = (async (context) => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo = await res.json()
  return { props: { repo } }
}) satisfies GetServerSideProps<{
  repo: Repo
}>
 
export default function Page({
  repo,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
  return repo.stargazers_count
}

언제 실행되는가?

getServerSideProps는 서버사이드에서만 실행되고 브라우저에서는 실행되지 않는다.

  • 페이지에 직접적으로 요청하면 요청한 타임에 실행되고 페이지는 return한 props로 pre-render를 진행한다.
  • 클라이언트 페이지 전환으로 실행될때 서버에 API응답을 보내준다.

언제 사용해야 하는가?

요청 시 데이터를 가져와야 하는 페이지를 렌더링해야 하는 경우에만 사용해야 한다. 만약 요청에 데이터를 렌더링할 필요가 없다면 client-side나 getStaticProps를 사용하는 것을 고려해야 한다

SSR에서 캐시 사용하기

ssr에서 header를 통해 캐시를 사용할 수 있다.

// This value is considered fresh for ten seconds (s-maxage=10).
// If a request is repeated within the next 10 seconds, the previously
// cached value will still be fresh. If the request is repeated before 59 seconds,
// the cached value will be stale but still render (stale-while-revalidate=59).
//
// In the background, a revalidation request will be made to populate the cache
// with a fresh value. If you refresh the page, you will see the new value.
export async function getServerSideProps({ req, res }) {
  res.setHeader(
    'Cache-Control',
    'public, s-maxage=10, stale-while-revalidate=59'
  )
 
  return {
    props: {},
  }
}

10초 동안은 신선한 값(fresh)이다. 10초에서 60초 사이에 요청이 반복되면 캐시된 값은 유효하지 않지만 API 요청을 이행하는 데 사용된다. 동시에 "백그라운드에서" 나중에 사용할 수 있도록 캐시를 새 값으로 채우기 위해 유효성 재확인 요청이 수행된다. 요청이 60초 이상 지난 후 반복되면 오래된 응답이 전혀 사용되지 않으며 브라우저의 요청을 이행하고 캐시 재검증이 모두 네트워크에서 응답을 받는 데 달려 있다.

profile
하다보면 안되는 것이 없다고 생각하는 3년차 프론트엔드 개발자입니다.

0개의 댓글