본문 바로가기

JavaScript/NextJS

NextJS - 사용해보기

 

1. NextJS?

  • React 프레임워크
  • SEO 최적화를 위한 SSR 구현 가능
    • React 만을 사용해서 SSR을 구현할 수 있지만, 이미 잘 갖춰진 프레임워크가 있는 상황에서 새로 구현하기엔 불필요한 비용이 발생
  • 이외에도 React 앱의 성능 향상을 위한 기능 제공
  • https://nextjs.org/learn/foundations/about-nextjs/what-is-nextjs

 

2. 프로젝트 생성

Next 프로젝트를 생성하는 데에는 두 가지 방법이 있습니다.

 

첫 번째로, 패키지를 직접 설치해서 세팅하는 방법입니다.

$ mkdir next-start && cd next-start
$ npm i react react-dom next

 

패키지를 설치하고 package.json의 script 항목을 수정합니다.

/* package.json */

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

 

그리고 pages라는 폴더를 만들고, 그 아래에 index.js 파일을 만들어주면 됩니다.

/* pages/index.js */

export default function Home() {
  return (
    <div>
      <h1>Home</h1>
    </div>
  );
}

 

두 번째로는, create-next-app을 사용하는 방법입니다.

$ npx create-next-app next-start

 

기본적으로 yarn을 사용하게 되는데, npm을 사용하고 싶다면 yarn을 설치 삭제해주면 됩니다.

npm uninstall yarn -g

 

3. 라우팅 설정하기

NextJS에서 라우팅 하는 방법은 정적 라우팅, 동적 라우팅의 두 가지 방법이 있습니다.

 

첫 번째로, 정적 라우팅은 파일 구조와 비슷하게 라우팅 시키는 방법입니다.

  • localhost:3000 : pages 폴더 바로 아래에 있는 index.js를 로드
  • localhost:3000/blog : blog 폴더에 있는 index.js를 로드
  • localhost:3000/blog/first-post : blog 폴더에 있는 first-post.js를 로드
  • localhost:3000/dashboard : dashboard 폴더에 index.js가 없으므로, 404 에러 화면 표시
  • localhost:3000/dashboard/username : username.js 파일을 로드

 

두 번째로, 동적 라우팅을 사용하는 방법입니다.

  • localhost:3000/blog/second-post : 동적 라우팅이 적용되어 [slug] 파일을 로드
  • localhost:3000/hyeonjun/settings : "/hyeonjun" 부분이 동적 라우팅되어 [username]/settings 파일을 로드
  • localhost:3000/post/a/b/c : "/a/b/c" 부분이 동적 라우팅되어 [...all] 파일을 로드( [slug]는 depth가 하나만 가능 )

 

동적 라우팅에서 경로 값을 가져오려면 아래와 같이 useRouter 훅을 사용해야 합니다.

import { useRouter } from 'next/router';

export default function Blog() {
  const router = useRouter();
  const { slug } = router.query;

  return (
    <div>
      <h1>Blog/{slug}</h1>
    </div>
  );
}

[...all]의 경우엔 여러 경로가 있을 수 있기 때문에 query가 배열 형태로 제공됩니다.

import { useRouter } from 'next/router';

export default function Post() {
  const router = useRouter();
  const { all } = router.query;
  
  return (
    <div>
      <h1>Post/{all.join("/")}</h1>
    </div>
  );
}

 

4. getStaticProps(), getStaticPaths(), getServerSideProps()

  • NextJS에는 정적 생성(SSG)서버 측 렌더링(SSR)의 두 가지 Pre-Render 방식이 있습니다. 둘의 차이점은 HTML 페이지를 생성하는 타이밍입니다. SSG는 빌드 시 HTML을 생성하고, SSR은 각 요청에 대해 HTML을 생성합니다.
  • 여기서 Pre-Render란, 서버에서 페이지 렌더링을 위한 최소한의 JavaScript를 사용해 페이지를 미리 생성해두는 방식을 말합니다. 
  • SSG 페이지에선 getSTaticProps(), getStaticPaths()가 사용되며, SSR 페이지에선 getServerSideProps()가 사용됩니다.
  • 이 함수들은 페이지를 생성하기 전, 데이터를 가져오기 위해 사용되며, 렌더링 속도가 빠른 SSG 방식이 권장됩니다.
  • https://nextjs.org/learn/basics/data-fetching/two-forms

 

getStaticProps()

프로덕션 빌드 시, 페이지에 필요한 데이터를 가져와서 컴포넌트에 전달해주는 함수입니다.

import { getSortedPostsData } from '../lib/posts';

export default function Home({ allPostsData }) { // getStaticProps로부터 전달받음
  return (
    <div>
      {allPostsData.map(({id, date, title}) => (
          <div key={id} style={{marginBottom:"30px"}}>
            {title}<br/>
            {id}<br/>
            {date}
          </div>
      ))}
    </div>
  )
}

export async function getStaticProps() {
  const allPostsData = getSortedPostsData();
  return {
    props: {
      allPostsData
    }
  }
}

 

getServerSideProps()

getStaticProps()의 경우엔 빌드 시에만 데이터를 가져오므로, 데이터가 자주 바뀌는 페이지에선 유용하지 않습니다. 각 요청 시마다 데이터를 가져와야 한다면 getServerSideProps()를 사용해야 합니다.

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 } }
}

 

getStaticPaths()

동적 라우팅 환경에서 데이터를 가져와야 하는 경우에 사용됩니다. getStaticProps()와 함께 사용해야 합니다.

import { useRouter } from 'next/router';
import { getAllPostIds, getPostData } from '../../lib/posts';

export default function Post({ postData }) {
  const router = useRouter();
  const {id} = router.query;
  return (
    <div>
      { postData.title }
    </div>
  )
}

export async function getStaticPaths() {
  const paths = getAllPostIds();
  /*
  paths = [
    { params: { id:1, ... } },
    { params: { id:2, ... } },
    ...
  ]
  */
  return {
    paths,
    fallback: false,
  }
}

export async function getStaticProps({ params }) {
  const postData = getPostData(params.id);
  return {
    props: {
      postData
    }
  }
}
  • getStaticPaths의 반환 객체의 값 중 paths는 빌드 시 만들어 놓을 페이지들의 목록(객체 배열)입니다. 이 페이지의 파일이 [id].js라면, params에 id 값이 있어야 합니다.
  • fallback은 true, false, 'blocking'을 사용할 수 있으며, paths에서 만들어 놓은 페이지가 아닌 페이지를 요청받으면 어떻게 처리할지에 대한 값입니다. https://velog.io/@mskwon/next-js-static-generation-fallback