본문 바로가기
Study/next.js

[Next] Next.js 핵심 기능 정리(Page Router 기준)

by 박히밍 2023. 12. 15.
반응형

[Next] Next.js 핵심 기능 정리(Page Router 기준)

 

 

[Next] Next.js 핵심 기능 정리(Page Router 기준)

 

 

Next.js 설치 방법

npx create-next-app@latest // 최신 버전 설치

npx create-next-app@12 // 12.3.4가 설치 된다.

 

 


 

 

 

Next.js 핵심 기능 정리

 

1. pages 파일 기반 라우팅(File Base Dynamic Routing)

Next.js는 File System 기반 라우팅을 제공한다.

파일 기반 라우팅 VS 코드 기반 라우팅

  • 파일 기반 라우팅(File-base)
    • 보일러 코드가 필요하지 않다.
    • 직관적이다.
    • 파일과 폴더의 구조가 라우팅에 영향을 미친다
  • 코드 기반 라우팅(Code-base)
    • 보일러 코드가 필요하다.(<Switch>, <Routes> … )
    • 라우팅의 개념에 대해 새롭게 배워야 한다.
    • 파일과 폴더 구조가 라우팅에 영향을 미치지 않는다.

 

 

1-1. 🗂pages 폴더 구조 개요

Next.js에서 pages 폴더는 React의 구성 요소이다.

각 페이지는 파일 이름을 기반으로 경로와 연결 된다. (Dynamic Routing)

파일 기반 라우팅 예시

 

1-2. index(🗂pages/index.js)

pages 폴더 하위에 index.js를 만들 경우 도메인의 첫 페이지(메인 페이지)가 된다.

 

1-3. Static Route(🗂pages/about.js)

pages 폴더 하위에 고정된 이름을 가진 파일(ex. about.js)를 만들 경우 정적 라우트 페이지가 생성된다. 파일명 기반으로 하위 페이지를 여러개 생성할 수 있다.

 

1-4. Nested Route(🗂pages/🗂 products)

pages 폴더 하위에 products라는 폴더를 생성하여 후 하위 페이지를 생성할 경우 여러 개의 페이지 파일들을 그룹화하여 경로를 자동으로 생성한다.

 

1-5. Dynamic Route(🗂pages/🗂 products/[id].js)

products 폴더 하위에 대괄호([])를 사용하여 js파일을 사용하면 별도의 설정 없이 다이나믹 라우팅 페이지가 생성된다.

id 값을 placeholder로 인식하여 상세(or 하위) 페이지가 동적으로 생성된다.

대괄호([]) 사이에는 아무 문자열이나 집어 넣어도 되지만 해당 하위 페이지의 경로와 데이터가 중복 될 수 없는 고유의 값(ID) 등을 기재 해주는 것이 바람직하다.

예) 🗂 products/[id].js or 🗂 postList/[postId].js

 

만약

이와 같은 형태일 때 경로를 http://localhost:3000/products/list 로 이동할 경우 id값을 가진 http://localhost:3000/products/[id] 로 이동하는 것이 아니라 /list 페이지로 이동하니 주의하자.

왜냐하면 폴더에는 list.js 라는 파일이 이미 존재하기 때문에 해당 파일을 우선 시 하기 때문이다.

 

Dynamic Route Segment Date 추출 방법

// 🗂pages/🗂products/[id].js

import { useRouter } from "next/router";

export default function ProductsItem() {
  const router = useRouter();

  console.log(router);
  return (
    <>
      <h1>ProductsItem page</h1>
      <p>this pathname: {router.pathname}</p>
      <p>this query: {router.query.id}</p>
    </>
  );
}

Dynamic Route Segment Date 추출

다이나믹 라우팅의 동적 segment를 추출 할 수 있다.

[id].js로 파일을 생성하였기 때문에 query는 query.id가 되었고 액세스 경로가 /products/1이기 때문에 query.id의 값이 “1”이 나왔지만,

만약 /products/someting으로 액세스 하였을 경우 query.id는 “something”이 되었을 것이다.

 

 

1-6. Catch-All Route(🗂 blog/[…slug].js)

pages 하위 폴더에 blog가 있다고 가정해보자. 만약 /blog의 하위 URL 경로 형식이 매우 다양하여

/blog/study도 있고, /blog/2022/07/10도 있을 때 이 형식을 다양하게 지원할 때 […blahblah].js 처럼 … 을 입력하면 페이지 경로를 확장성 있게 생성해준다.

// 🗂 blog/[…slug].js

import { useRouter } from "next/router";

export default function Blog() {
  const router = useRouter();

  console.log(router);

  return (
    <>
      <h1>Blog page</h1>
      <p>this pathname: {router.pathname}</p>
      <p>this query: {router.query.slug}</p>
    </>
  );
}

Catch-All Route 예시 1
Catch-All Route 예시 2

useRouter 를 이용하여 query를 출력해본 결과 query.slug는 슬래시(/) 기준으로 배열 형태로 segment의 개수가 동적으로 생성된 것을 확인할 수 있다.

 

 

1-7. Nested Dynamic Route 중첩 동적 라우트 (🗂pages/🗂 [nested_dynamic]/[test].js)

pages 하위에 대괄호로 감싼 아무 문자열을 가진 폴더를 생성 한 뒤 그 안에 다이나믹 라우터 파일을 생성해주었다고 가정해보자.

이럴 경우 http://localhost:3000/를 기점으로 하위 경로를 모두 동적으로 불러올 수 있게 설정이 된다.

import { useRouter } from "next/router";

export default function NestedDynamic() {
  const router = useRouter();

  console.log(router);

  return (
    <>
      <h1>Nested-Dynamic page</h1>
      <p>this pathname: {router.pathname}</p>
      <p>this query: {router.query.nested_dynamic}</p>
      <p>this query: {router.query.test}</p>
    </>
  );
}

 

query는 서로 다르지만 동일한 페이지 컴포넌트를 보여주고 있다.

Nested Dynamic Route 중첩 동적 라우트를 사용할 경우 query의 형태는 객체 형태로 전달된다.

만약 /2023/07/10 경로로 이동할 경우 404 페이지가 뜰 것이다. 왜냐하면 Catch-All Route와는 다르게 하위 경로의 개수까지 동적으로 확장하진 않기 때문이다.

 

 

 


 

 

 

2. pages 사전 렌더링(Rre-Rendering) & 데이터 패칭(Date Fetching)

Next.js를 사용하려면 SSR의 개념과 Hydrate의 개념에 대해 숙지하고 가야 한다.

SSG와 Hydrate란?

Next.js는 앱을 빌드하는 시점에 사전 생성한 정적 페이지(Pre-rendering)와 번들링 된 JS파일을 Server Side단에서 클라이언트로 보낸 뒤, 클라이언트단에서 전달받은 HTML 코드와 React의 JS 코드를 서로 매칭하는 것을 Hydrate라고 한다. Hydrate를 통해 클릭과 같은 이벤트나 모듈들이 HTML 정적 페이지에 각각 자신의 자리를 찾아가게 되고 사용자 조작이 가능케 하는 것이다.

 

 

2-1. Next.js Data Fetching 함수의 종류

⭐️ getStaticProps

빌드 시 외부 데이터를 fetch하여 정적 페이지를 생성(Static Generation)하는 함수이다.

반드시 return되는 값은 객체여야 한다.

호출 시 마다 매번 Data를 fetch하지 않아서 getServerSideProps 보다 성능면에서 좋다.

getStaticProps 기본 구성

export default function Blog({ posts }) {
  // 렌더링 될 함수
}

export const getStaticProps = async () => {
	// API 함수를 실행
  const res = await fetch('https://jsonplaceholder.typicode.com/posts')
  const posts = await res.json()

	// { props: { repo } }를 반환함으로써, Blog 컴포넌트는 posts라는 props를 빌드 시점에 얻는다.
  return { props: { posts} } // return 되는 값은 객체여야 함
}

언제 사용하지?

  • 클라이언트에게 페이지를 전달해주기 전 API 요청으로 데이터를 불러 온 뒤 정적 페이지를 생성 해야할 때
  • SEO를 위해 속도 빠른 페이지가 필요할 때
  • 정적 생성을 해야 할 때
    • 예) 마케팅 페이지 / 블로그 게시물 및 포트폴리오 등

 

 


 

 

⭐️ getStaticPaths (with getStaticProps)

페이지가 동적 라우팅(Dynamic Routing), getStaticProps를 사용하는 경우에 정적으로 렌더링 할 경로를 설정하기 위한 함수. getServerSideProps와 함께 사용할 수 없고 반드시 getStaticProps와 함께 사용해야 함

 

빌드 시점에 실행 된다.

예를 들어 pages/posts/[id].js 과 같은 폴더 구조가 있을 때 Next.js는 자동으로 pages를 찾아 Routes를 구성한다.

 

아래와 같이 동적 경로(paths)와 데이터를 같이 받을 때 사용한다.

getStaticPaths 기본 구성

export default function Blog({ posts }) {
  // 렌더링 될 함수
}

export async function getStaticPaths() {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts}`);
  const posts = await res.json();

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

  return {
    paths,
    fallback: false, //필수값. false는 paths에 포함되지 않은 경로일 때 404 리턴
  };
}

export async function getStaticProps({ params }) {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}`);
  const postData = await res.json();

  return {
    props: {
      postData,
    },
  };
}

getStaticProps 함수가 params를 받아 미리 생성된 paths를 캐싱하여 라우터로 페이지를 이동할 때 빠른 렌더링 속도를 보여준다.

 

언제 사용하지?

  • 동적 경로를 사용하고 getStaticProps를 사용할 때(반드시 getStaticProps와 사용해야 함)

 

 

 


 

 

⭐️ getServerSideProps

사용자가 클라이언트로 요청할 때 마다 실행되는 함수. 서버 측에서만 실행되며 브라우저(클라이언트)에서는 실행되지 않는다.

데이터가 동적이고 업데이트가 빈번할 때 사용한다.

매 요청 시 마다 호출되어서 비용이 많이 발생한다는 단점이 있으나, 동적인 데이터를 사전 렌더링 해야 하는 경우에 적합하다.

 

getServerSideProps 기본 구성

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

export const getServerSideProps = async () => {
  // 동적 데이터를 가진 API 호출
  const res = await fetch(`https://.../data`)
  const data = await res.json()
 
  // Page로 props를 이용해 data 전달
  return { props: { data } }
}
 
export default Page

언제 사용하지?

  • 페이지의 데이터가 항상 최신 상태를 유지해야 하는 경우
  • 요청에 따라 응답 내용이 시시각각 변할 때

 

 

참고 :: getInitialProps는 사장 중이라 (공식 문서에서 권고하지 않으니까) 정리하지 않음

 

 

 


 

 

2-2. Next.js 렌더링 방식 요약

🌱SSR🌱

서버에서 데이터를 가져와 요청 시 마다 데이터를 페이지로 props를 통해 전달

사용 함수: getServerSideProps

 

🌱CSR🌱

기존에 React에서 사용하던 클라이언드 사이드 렌더링 방식

 

🌱SSG🌱

빌드 시점에 데이터를 가져 와 정적 페이지를 생성한다.

사용 함수: getStaticProps + getStaticPaths

 

🌱ISR🌱

정적 사이트로 생성 해 놓고 특정 주기로 데이터를 가져와서 다시 그려준다. (SSR + SSG의 장점을 합친 것)

ISR을 사용하면 전체 사이트를 재배포할 필요 없이 페이지별로 정적 생성을 할 수 있다.

사용 함수: getStaticProps(+revalidate)

export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()
 
  return {
    props: {
      posts,
    },
    // Next.js가 페이지 재생성을 시도한다:
    // - 10초에 한 번씩 요청이 들어올 때마다.
    revalidate: 10, // 초 단위
  }
}

 

반응형