강디너의 개발 일지

Next.js 데이터 가져오는 방법 (Data Fetching) 본문

Javascript/React.js

Next.js 데이터 가져오는 방법 (Data Fetching)

강디너 2022. 8. 22. 01:09
728x90

Next.js 에서 데이터를 가져오는 방법이 여러 가지 있습니다.

  • getServerSideProps
  • getStaticPaths
  • getStaticProps

Next.js에서는 서비스에 따라 다양한 방식으로 콘텐츠를 렌더링 할 수 있도록 지원해주는데 SSR, SSG, CSR, ISR 이 있습니다. 이러한 방식에 따라 데이터 패칭 하는 방식이 다릅니다.(사용하는 함수도 달라요.)

 

 

getServerSideProps - SSR 공식문서

서버에서만 실행되고, 브라우저에서는 실행되지 않기 때문에 브라우저에 로그가 찍히지 않습니다.

/*
    context object 에 있는 데이터
    
    params: 페이지가 동적 경로일 경우 - 페이지 이름이 [id].js일 경우 params는 { id: 값 }
    req: HTTP request object
    res: HTTP response object
    query: 동적 경로 매개변수를 포함한 query의 값
    preview: 페이지가 Preview Mode일 경우 true
    previewData: setPreviewData에서 설정한 데이터
    등등...
*/

export async function getServerSideProps(context) {
  return {
    props: {}, 				// 컴포넌트가 받을 props
    revalidate: 0, 			// 페이지가 재생성될 지연 시간
    notFound: false,			// true일 경우 404
    redirect: { 			// 리다이렉트할 페이지의 경로
    	destination: '/'   		// 리다이렉트 경로
    },
  }
}

*pre-render란 빌드할 때 특정 페이지를 미리 HTML을 만들어주는 기능

 

getServerSideProps 페이지만 사용 가능합니다. 페이지가 아닌 파일에서는 사용할 수 없습니다. 

(_app, _document, _error 등 / 문서에서는 페이지 내에서만 export 할 수 있다고 적혀있네요.) 

 

getServerSideProps 는 서버에서만 실행되어서 브라우저에서 로그를 확인할 수 없습니다.(불편...)

 

getServerSideProps 가 선언된 페이지는 빌드와 상관없이 매번 페이지에 들어올 때마다 데이터를 서버에 요청합니다.  그리고 반환한 props를 이용해서 렌더링 합니다. 

(next/link, next/router를 이용한  페이지 이동인 경우)

 

getServerSideProps 는 데이터 변경이 잦고, 개인화된 사용자 경험이 필요할 때 사용합니다.

(예를 들면 와디즈의 홈처럼 새로운 데이터가 중요하고, AI 추천 같이 사용자마다 보여줘야 하는 경우가 다를 경우)

 

getServerSideProps 는 자주 업데이트가 필요한 데이터가 포함되어있는데, pre-render 할 필요가 없는 경우 추천하지 않습니다. 문서에서는 클라이언트 측에서 데이터를 가져오라고 권합니다. 이런 경우를 예를 든 것이 대시보드 페이지입니다.

SEO가 필요 없기 때문에 pre-render 할 필요도 없고, 데이터도 자주 업데이트되기 때문에 useEffect를 이용한 클라이언트 사이드 데이터 패칭을 추천합니다.

 

 

getStaticProps - SSG 공식문서

서버에서만 실행되고, 브라우저에서는 실행되지 않기 때문에 브라우저에 로그가 찍히지 않습니다.

/*
    context object 에 있는 데이터
    
    params: 페이지가 동적 경로일 경우 - 페이지 이름이 [id].js일 경우 params는 { id: 값 }
    req: HTTP request object
    res: HTTP response object
    query: 동적 경로 매개변수를 포함한 query의 값
    preview: 페이지가 Preview Mode일 경우 true
    previewData: setPreviewData에서 설정한 데이터
*/


export async function getStaticProps(context) {
  return {
    props: {}, 				// 컴포넌트가 받을 props
    revalidate: 10, 			// 페이지가 재생성될 지연 시간
    notFound: false,			// true일 경우 404
    redirect: { 			// 리다이렉트할 페이지의 경로
    	destination: '/'   		// 리다이렉트 경로
    },
  }
}

 

getStaticProps 는 SSG로 만들기 위해 사용하며, 프로젝트가 빌드될 때 데이터를 가져옵니다.(SEO에 유리)

빌드 시 데이터를 미리 받아오기 때문에 매우 빠른 속도로 페이지에 렌더링 합니다.

 

getStaticProps 를 사용하면 서버 측에서만 실행되기 때문에 JS 번들에도 포함되지 않고, 데이터베이스 쿼리를 작성할 수 있습니다.

 

getStaticProps  페이지만 사용 가능합니다. 페이지가 아닌 파일에서는 사용할 수 없습니다. 

(_app, _document, _error 등) 

 

getStaticProps 는 getServerSideProps 와 다르게 매번 데이터를 요청하지 않기 때문에 업데이트가 잦지 않은 static한 페이지일 경우 추천합니다.

 

getStaticProps 는 유저 단위가 아닌 공통으로 캐시가 될 수 있는 데이터를 사용할 때 유리합니다. 

예를 들어 블로그 포스트 같이 이미 데이터는 정해져 있고, 페이지에서는 해당 포스트만 보여주고 변동이 많이 없을 때 추천합니다.

 

 

 

getStaticPaths - SSG 공식문서

동적 경로를 이용해서 페이지를 만들고 싶은데 SSG를 사용하고 싶다.  getStaticProps 를 같이 사용하면서 빌드 타임 때 정적으로 렌더링 할 path를 설정해줍니다.

// pages/posts/[id].js

export async function getStaticPaths() {
	const res = await fetch(...);
    const posts = await res.json();
    
    const paths = posts.map((post)) => ({
    	params: { id: post.id }
    });
    return {
	paths,			// 빌드타임에 pre-render 할 경로들
        fallback: false,	// ture or 'blocking'   -> 자세한건 아래에서 설명
    }
}

// `getStaticPaths` requires using `getStaticProps`
export async function getStaticProps(context) {
  return {
    // Passed to the page component as props
    props: { post: {} },
  }
}

// router.isFallback를 이용해서 Fallback이 렌더링되고 있는지 감지
export default function Post({ post }) {
  const router = useRouter()

  // If the page is not yet generated, this will be displayed
  // initially until getStaticProps() finishes running
  if (router.isFallback) {
    return <div>Loading...</div>
  }

  // Render post...
}

getStaticPathsgetServerSideProps 와 사용할 수 없습니다. 무조건 getStaticProps 와 함께 사용해야 합니다.

 

getStaticPaths 는 paths와 fallback을 반환하는데, paths는 빌드 타임에 pre-render 할 경로들이고, fallbackfalse, true, 'blocking'를 반환합니다.

 

fallback

  • false 인 경우  paths에 등록되지 않은 경로로 들어가면 404 페이지가 됩니다. 이 옵션은 생성할 path가 적거나 새로운 페이지가 자주 추가되지 않는 경우에 유용합니다.
  • true 인 경우 paths에 등록되지 않은 경로로 들어가면 404 페이지가 되는 대신에 별도의 컴포넌트를 보여줄 수 있습니다.(router.isFallback으로 감지) 그 후 getStaticProps 를 통해 데이터를 가져오고 props를 가져오면 정적 페이지를 생성합니다. 당시에는 pre-render가 되지 않지만 한번 렌더링 후부터는 pre-render에 포함됩니다. (와디즈의 펀딩처럼 계속적으로 상품이 등록될 때 유용한 기능입니다.)
  • 'blocking' 인 경우 paths에 포함되지 않은 경로는 SSR과 동일하게 생성합니다. getStaticPaths 가 될 때까지 기다린 다음 성공하면 해당 페이지 경로를 캐싱한 후 다음 요청 시에는 캐싱된 데이터를 리턴합니다. true와 동일하게 한번 렌더링 후부터는 pre-render가 됩니다.

 

Incremental Static Regeneration 공식문서

ISR 방식이 무엇이냐.

getStaticProps 함수를 이용해서 SSG 방식으로 만들면 빌드 시점에 페이지가 생성되지만, ISR 방식은 일정 주기마다 데이터의 최신 여부를 검사하고 업데이트된 데이터로 페이지를 다시 생성합니다.

 

ISR 방식을 이용하면 전체 사이트를 다시 빌드할 필요 없이 최신 데이터로 정적 페이지를 만들 수 있습니다.

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{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

 

getStaticProps 의 props에 revalidate를 추가하고, getStaticPaths 는 'blocking' 이어야 합니다.

revalidate 값이 10이면 모든 사용자는 10초 동안 생성된 동일한 버전의 사이트를 봅니다. 캐시를 초기화하는 방법은 10초가 지난 후 누군가가 해당 페이지를 방문하면 캐시가 초기화되어서 새로 업데이트된 페이지를 볼 수 있습니다.

(상품의 가격, 성명, 리뷰 등)

 

ISR 방식은 SSG의 성능상 이점을 챙기면서도 사용자에게는 업데이트된 콘텐츠를 제공할 수 있습니다.

 

 

 

커피한잔...
Comments