[Next] Next.js 시작하기

jaemin·2021년 8월 1일
0

넥스트

목록 보기
1/1
post-thumbnail

Next.js 시작하기

📌 프로젝트 Setup

Next.js는 create-next-app을 이용하여 어플리케이션을 생성하는 것을 권장합니다. create-next-app은 set up에 필요한 것들을 자동적으로 준비해줍니다. 만약 타입스크립트를 사용하고 싶다면 --typescript 플래그를 사용하세요.

npx create-next-app
# 혹은
yarn create next-app

npx create-next-app --typescript
# 혹은
yarn create next-app --typescript

만약 기존 프로젝트에 next를 추가한다면 다음과 같이 할 수 있습니다. next, react, react-dom을 설치해주세요.

npm install next react react-dom
# 혹은
yarn add next react react-dom

package.json을 열고 scripts를 수정해주세요.

"scripts": {
  "dev": "next dev",
  "build": "next build",
  "start": "next start",
  "lint": "next lint"
}

📌 Pages

Next.js는 **pages**개념을 기반으로 구축되었습니다. 어플리케이션의 페이지들은 pages 디렉토리 안의 js, jsx, ts, tsx 파일 안의 리액트 컴포넌트를 렌더링합니다. Next는 pages 디렉토리 안의 파일들을 코드 스플리팅된 컴포넌트로 만들어주므로 디렉토리 이름은 항상 pages여야 합니다.

각각의 페이지들의 라우트 이름은 파일 이름과 연관이 있습니다. 예를 들어, pages디렉토리 안에 about.js 파일이 있다면 라우터 이름은 /about이 됩니다. 동적으로 바뀌는 라우트 또한 사용할 수 있습니다. pages/posts/[id].js 파일 이름을 이런식으로 작성하면, 동적으로 변하는 라우터를 만들 수 있습니다. posts/1, posts/2.. 등이 가능합니다.

어플리케이션을 구동하기 위해 npm run dev 혹은 yarn dev를 실행합니다. http://localhost:3000에 들어가면 보이는 화면은 pages/index.js 파일입니다.

📌 Pre-rendering

기본적으로 Next.js는 모든 페이지를 미리 렌더링(pre-rendering)합니다. react는 최초에 비어있는 HTML 하나만 서버에서 받은 후 모든 것을 클라이언트 사이드에서 렌더링하는 반면, Next.js는 미리 각 페이지들의 HTML을 생성해둡니다. 이렇게 되면, Pre-rendering으로 인해 검색 최적화와 더 나은 성능을 가져올 수 있습니다.

두 가지 형식의 Pre-rendering

Next는 Static GenerationServer-side Rendering 두 가지 형태의 pre-rendering이 있습니다. 이 둘은 페이지들의 HTML을 언제 생성하느냐에 따라 다릅니다.

  • Static Generation (추천)

HTML을 build 할 때 생성하고 요청할때 이를 재사용합니다.

  • Server-side Rendering

요청할 때마다 HTML을 생성합니다.

중요한 점은, 여러분이 어떤 방식으로 pre-rendering 할 것인지 정할 수 있습니다. 대부분의 페이지는 Static Generation 방식을 사용하고 다른 것들은 서버 사이드 렌더링 방식을 사용해서 하이브리드 next app을 만들 수 있습니다.

static generation 방식은 추가적인 작업 없이 CDN에서 캐시할 수 있기 때문에 next는 이 방식을 추천합니다. 이 두 가지 pre-rendering 방식과 함께 react처럼 클라이언트 사이드 렌더링을 사용할 수도 있습니다.

CDN이란?
CDN은 서버와 사용자 사이의 물리적 거리를 줄여 웹 페이지의 로드 지연을 최소화하는, 촘촘히 분산된 서버로 이루어진 플랫폼입니다.

Static Generation은 어플리케이션을 build 할 때 생성한다고 했습니다. next에서는 데이터가 있을때도, 그리고 데이터가 없을 때도 정적으로 페이지를 만들 수 있습니다. 각각의 경우를 통해 알아봅시다.

data fetching이 없을 때 Static Generation

기본적으로 next는 데이터를 가져오지 않고 static generation을 사용하여 페이지를 미리 렌더링합니다.

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

export default About

data fetching을 하지 않는다면 문제될 게 없어보입니다. data fetching이 있는 경우는 어떨까요?

data fetching이 있을 때 Static Generation

어떤 페이지들은 pre-rendering을 위해 데이터를 가져와야 합니다. 데이터를 가져오는 경우는 크게 두 가지가 있고 각각의 경우에, next가 제공해주는 함수를 사용할 수 있습니다.

  1. 페이지의 내용이 외부 데이터에 의존한다 => getStaticProps 사용

  2. 페이지의 경로가 외부 데이터에 의존한다 => getStaticPaths 사용

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

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

export default Blog

props로 정보를 받아 렌더링 해주는 컴포넌트가 있다고 할때, pre-render를 하기 전에 데이터를 받아와야 합니다. 이때 getStaticProps를 사용할 수 있는데 이 함수는 build 타임에 호출되고 받아온 데이터를 Pre-render 할 때 전달해줍니다.

function Blog({ posts }) {
  // posts 렌더링
}

// 이 함수는 build time에 호출됩니다.
export async function getStaticProps() {
  // 외부 api 호출
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // { props: { posts } }를 반환함으로써,
  // `posts`를 build time에 prop으로 받을 수 있습니다.
  return {
    props: {
      posts,
    },
  }
}

export default Blog

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

앞서 말했듯이 next에서는 동적 라우트를 사용해서 페이지를 만들 수 있습니다. 예를 들어, pages/posts/[id].js 라는 파일을 생성하고 posts/1 주소로 접근한다면 id를 1로 인식하여 페이지가 렌더링됩니다.

이 paths가 동적으로 받아온다면 다음과 같이 쓸 수 있습니다.

// getStaticPaths도 build 타임에 호출됩니다.
export async function getStaticPaths() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // { fallback: false}는 다른 라우터는 404여야 한다는 것을 뜻합니다.
  return { paths, fallback: false }
}

pages/posts/[id].js에서 getStaticProps를 사용하여 특정 id 값을 props로 받도록 합니다.

function Post({ post }) {
  // posts 렌더링
}

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

export async function getStaticProps({ params }) {
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()

  return { props: { post } }
}

export default Post

Server-side Rendering

만약 Server-side Rendering을 사용한 페이지라면, 매 요청마다 HTML이 생성됩니다. server-side rendering을 사용하고 싶은 페이지에서 getServerSideProps라는 비동기 함수를 export하면, 서버는 이 함수를 요청이 올때마다 호출합니다.

function Page({ data }) {
  // 데이터 렌더링
}

// 이 함수는 매 request마다 호출됩니다
export async function getServerSideProps() {
  // 외부 API로부터 데이터를 가져옵니다
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  // props를 통해 데이터를 넘겨줍니다(getStaticProps와 유사)
  return { props: { data } }
}

export default Page

Static Generation 방식과 비슷하지만 다른 점은 getStaticProps는 빌드 타임에 호출되고 getServerSideProps는 매 요청마다 호출된다는 것입니다.

📌 언제 Static Generation을 사용해야 할까요?

next는 가능하면 Static Generation을 사용하는 것을 권장합니다. CDN으로부터 받은 데이터를 한 번만 빌드할 수 있다면 모든 요청마다 서버에서 렌더링하는 것보다 훨씬 빠르고 적은 리소스를 사용할 수 있기 때문입니다.

마케팅 페이지, 블로그 포스트, 이커머스 상품의 리스트, 도큐먼트 페이지 등 많은 타입의 페이지에서 Static Generation을 사용할 수 있습니다.

스스로에게 물어봅시다. "사용자의 요청 전에 이 페이지가 pre-render 될 수 있는가?" 이 질문의 대답이 YES라면, Static Generation을 통해 퍼포먼스와 SEO 측면으로 많은 이점이 생길 것입니다.

반면, 사용자 요청 이전에 pre-render 할 수 없다면 Static generation은 좋은 생각이 아닙니다. 여러분의 페이지의 데이터가 자주 업데이트 되고 페이지의 컨텐트가 매 요청마다 바뀌는 경우가 여기에 해당됩니다. 이런 경우, 다음 두 가지 방법이 있습니다.

  • Static GenerationClient-side Rendering 함께 사용 : 페이지의 일부분을 pre-rendering 하지 않고 그 부분을 client-side에서 자바스크립트 코드를 동작시켜 구성할 수 있습니다.

  • Server-side Rendering 사용: 모든 요청마다 페이지를 pre-render 할 수 있습니다. 이 방법은 CDN에 의해 페이지가 캐싱될 수 없기 때문에 느리지만 항상 최신 상태를 유지합니다.

📋 Reference

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

profile
프론트엔드 개발자가 되기 위해 공부 중입니다.

0개의 댓글