상세 컨텐츠

본문 제목

[Next.js] 2. Pages와 렌더링 방식 정리

NextJS

by hong_2 2021. 8. 27. 12:23

본문

Pages

Next.js에서 page 는 `.js`, `.jsx`, ' .ts'에서 내보내진 리액트 컴포넌트이다.

만약 `pages/about.js`와 같이 pages 디렉토리에 js 파일을 생성하게 되면 `/about` url 을 통해 접근이 가능하다.

function About() {
  return <div>About</div>
}

export default About

 

Pages with Dynamic Routes (동적 라우팅)

Next.js는 동적 라우팅을 지원한다. 예를 들어 `pages/posts/[id].js` 와 같은 파일을 생성하게 되면

`posts/1`, `posts/2`와 같이 동적으로 접근이 가능하다.

 

Two forms of pre-rendering

Next.js는  정적 생성(Static Generation)과 서버 사이드 렌더링 (Server-side Rendering 이하  SSR), 두가지 형태의 pre-rendering(이하 사전 렌더링)을 지원한다.

  • Static Generation(추천) : HTML 파일이 프로젝트를 빌드할때에 생성되며 각 요청에 따라 재사용이 된다.
  • Server-side Rendering: HTML 파일이 각 요청이 있을때 생성된다.

Next.js는 사용자의 목적에 맞게 pre-rendering을 고를 수 있게 해주며, 상황에 따라 둘을 혼용하여 하이브리드 앱을 만들 수 도 있다.

 

효율성의 측면에서는 SSR보다는 Static Generation을 추천한다.

Static Generation을 통해 정적으로 생성된 페이지들은 CDN(Content Delivery Network)에 캐시가 되어 효율 향상에 추가적인 설정이 필요하지 않다. 하지만 때에 따라 SSR을 사용할 수 밖에 없는 경우도 있다.

 

Next.js에서는 Static Generation, SSR 뿐만 아니라 Client-side Rendering도 가능하다.

 

 

Static Generation (추천)

Static Generation을 사용하게 되면 HTML 파일은 프로젝트가 빌드될때 생성이 된다. 즉, HTML 페이지가 

`next build` 란 명령어가 실행됬을때 생성된다는 뜻이다. 이렇게 생성된 HTML 파일은 CDN에 의해 캐시되어 요청이 있을 때마다 재사용되게 된다.

 

Static Generation without data

기본적으로 Next.js는 정적 생성을 통해 데이터가 없이 사전 렌더링을 한다.

function About() {
  return <div>About</div>
}

export default About

이 페이지의 경우 외부 데이터를 가져오지 않고 사전 렌더링 된다는 것을 알아두자. 이때 Next.js는 빌드 간 단일 HTML 파일만을 생성한다.

 

 

Static Generation with data

몇몇 페이지는 사전 렌더링을 위해 외부 데이터를 필요로 한다. 아래 두가지의 경우에 Next.js에서 제공하는 함수를 각각 이용 할 수 있다.

  1.  페이지의 내용이 외부 데이터에 의존할때 :  `getStaticProps` 를 사용
  2.  페이지의 경로가 외부 데이터에 의존할때: `getStaticPaths`( 보통은 `getStaticProps`도 같이 쓰임)

 

1. 페이지의 내용이 외부 데이터에 의존할때

예제:  블로그 페이지의 블로그 포스트가 CMS(content management system)을 통해 가져와지는 경우.

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

export default Blog

 

사전 렌더링을 통해 데이터를 가져올때  같은 파일 내에서 asysnc 함수를 통해 `getStaticProps`를 호출할 수 있다.

이 함수는 빌드될 때 요청을 받고 사전 렌더링시 페이지의 `props`로 데이터를 가져올 수 있다.

function Blog({ posts }) {
  // Render posts...
}

// This function gets called at build time
export async function getStaticProps() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // By returning { props: { posts } }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      posts,
    },
  }
}

export default Blog

 

2. 페이지의 경로가 외부 데이터에 의존할때

Next.js는 동적 라우팅(dynamic routes)를 지원한다. 예를 들어 `pages/posts/[id].js`를 만들게되면 id 변수값에 따라 다른 포스트를 보게 된다.  하지만 빌드될 때 사전렌더링 되야하는 id는 외부 데이터에 의존적이다.

 

예제: 만약 데이터베이스에 오직 하나의 포스글이 추가 됬다고 생각했을때, 우리는 `posts/1`과 같이만 사전 렌더링을 해주면 된다. 추후 두번째 포스트글이 추가 된다면 `posts/2`를 사전 렌더링해주면 된다. 

즉, 페이지의 경로가 외부 데이터에 의해 결정되게 되는 것이다. 페이지의 경로가 외부 데이터에 의존적일 경우,

`getStaticPaths` 함수를 통해 우리가 사전 렌더링하고 싶은 경로를 지정할 수 있다.

// This function gets called at build time
export async function getStaticPaths() {
  // Call an external API endpoint to get posts
  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: false } means other routes should 404.
  return { paths, fallback: false }
}

또한 `pages/posts/[id].js` 파일에서 포스트의 id값을 가져오기와서 사용하기 위해  `getStaticProps`를 호출 할 수도 있다.

function Post({ post }) {
  // Render post...
}

export async function getStaticPaths() {
  // ...
}

// This also gets called at build time
export async function getStaticProps({ params }) {
  // params contains the post `id`.
  // If the route is like /posts/1, then params.id is 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()

  // Pass post data to the page via props
  return { props: { post } }
}

export default Post

 

When should I use Static Generation?

한번의 빌드와 CDN의 지원을 받기 위해서는 가능한 정적 생성을 사용하는 것을 추천한다. 이는 매 요청마다 서버 렌더링을 하는 것보다 훨씬 더 빠르기 때문이다.

 

Static Generation 은 다음과 같이 다양한 형태의 페이지에서 사용할 수 있다:

  • 마케팅 페이지
  • 블로그 포스트
  • 이커머스 상품 리스트
  • 고객센터 및 문서

사용자의 요청에 앞서 미리 렌더링을 할 수 있는 경우에는 정적 생성을 선택할 수 있다.

 

반면에 정적 생성은 사용자의 요청에 앞서 페이지를 미리 렌더링할 수 없는 경우 좋은 생각이 아니다.

페이지에 자주 업데이트되는 데이터가 표시되고 모든 요청에 ​​따라 페이지 콘텐츠가 변경될 수 있다.

이 경우에는:

  • 정적 생성과 Client-side-Rendering을 함께 사용한다.
  • Server-Side Renderiing을 사용한다. 

 

쉽게 이야기해서 상세페이지와 같이 내용이 많이 바뀌지 않는 페이지의 경우는 정적 생성(Static Generation)를 사용하고,  수시로 데이터가 바뀌고 요청에 따라 페이지의 콘텐츠가 바뀌는 동적인 경우는 정적 생성과  CSR을 같이 쓰거나 SSR을 사용하면 된다.

 

Server-Side Rendering( SSR or Dynamic Rendering)

서버사이드 렌더링을 통해 페이지를 렌더링 할 경우 HTML 파일이 각 요청이 있을때 마다 생성된다.

서버사이드 렌더링을 하기 위해서는 `getServerSideProps` 함수를 호출하면 된다.

 

예를들어, 외부 API 통신을 통해 데이터를 가져와 자주 화면을 사전 렌더링해야할 경우가 있다고 가정해보자.

이 경우 다음과 같이 `getServerSideProps`를 통해 데이터를 가져올 수 있다.

function Page({ data }) {
  // Render data...
}

// This gets called on every request
export async function getServerSideProps() {
  // Fetch data from external API
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  // Pass data to the page via props
  return { props: { data } }
}

export default Page

언뜻보면 정적 생성의 `getStaticProps`와 유사하게 보일수 있으나 `getServerSideProps`의 경우 빌드할때 실행되는 것이 아니라 각 모든 요청이 있을 때 실행된다.

 

 

요약

  • Static Generation(정적 생성 - 추천) : HTML 파일이 빌드시에 생성되며 각 요청이 있을때마다 재사용된다. 정적 생성을 통해 페이지를 만들때에는 컴포넌트 자체를 내보내거나 `getStaticProps`를 통해 데이터를 가져와서 내보내야한다. 또한 정적 생서은 사용자의 요청에 앞서 렌더링이 가능할때 사용하는 것이 좋다. 
  • Server-Side Rendering: HTML 파일이 각 요청이 있을때 생성된다. 서버 사이드 렌더링을 하기 위해서는 `getServerSideProps` 함수를 사용하면된다. 서버 사이드 렌더링의 경우 요청이 있을 때마다 HTML 파일을 생성하므로 정적 생성보다 느리므로 꼭 필요한 곳에만 사용하도록 하자.

 

참고자료

https://nextjs.org/docs/basic-features/pages

관련글 더보기

댓글 영역