[NextJS] 프로젝트 생성 with TypeScript

상민·2022년 7월 12일
2

NextJS with TypeScript

목록 보기
2/6
post-thumbnail

프로젝트 생성

NextJS + TypeScript 프로젝트를 생성해보자.

터미널에 아래 명령어를 입력한다.

npx create-next-app --typescript 프로젝트명

해당 명령어를 입력하고 프로젝트 폴더로 이동하면 아래와 같은 구조로 프로젝트가 생성된다.

여기서 중요한 폴더는 pages public styles 가 있다.
styles는 스타일 파일들이 들어있다.
public폴더를 보면 일반적인 React 앱과는 다르다는걸 알 수 있다.

CRA(create-react-app)으로 리액트 앱을 만들면 public 폴더에서 index.html을 찾아볼 수 있는데 NextJS 앱에는 그게 없다.
NextJS는 사전 렌더링 기능을 내장하기 때문이다.

NextJS는 SPA를 제공하여 서버에 요청이 오면 이 SPA에 동적으로 사전 렌더링을 거쳐 콘텐츠를 포함한 초기 페이지를 보여주게 된다.

pages폴더는 파일 기반 라우팅을 설정하고 애플리케이션을 구성할 여러 페이지를 정의한다.


페이지 생성

NextJS에 페이지를 추가해 보자.

  • pages/index.tsx

import type { NextPage } from 'next'

const Home: NextPage = () => {
  return (
    <h1>Home Page</h1>
  )
}

export default Home

터미널에 npm run dev 명령어를 입력해서 localhost:3000에서 결과를 확인해보자.

이번에는 pages폴더에 news.tsx 파일을 추가해 보자.

  • pages/news.tsx

import type { NextPage } from 'next'

const News: NextPage = () => {
  return (
    <h1>
      News Page
    </h1>
  );
};

export default News;

해당 컴포넌트는 localhost:3000/news주소를 입력해 브라우저에서 접근할 수 있다.

이번에는 중첩 라우팅을 해보자

pages폴더에서 news.tsx파일을 삭제하고 news폴더를 생성한다.
해당 news폴더에서 index.tsx와 detail.tsx를 생성한다.

  • pages/news/index.tsx

import type { NextPage } from 'next'

const News: NextPage = () => {
  return (
    <h1>
      News Page
    </h1>
  );
};

export default News;
  • pages/news/detail.tsx

import type { NextPage } from 'next'

const Detail: NextPage = () => {
  return (
    <h1>
      Detail Page
    </h1>
  );
};

export default Detail;

News 컴포넌트는 이전과 마찬가지로 localhost:3000/news로 접근할 수 있고 Detail 컴포넌트는 localhost:3000/news/detail로 접근할 수 있다.


동적 페이지 라우팅

이번에는 매개변수를 이용한 동적 페이지를 만들어 보자.

news폴더에서 detail.tsx의 이름을 [newsId].tsx라고 수정한다
동적 페이지 라우팅을 사용하기 위해서는 컴포넌트 이름에 대괄호가 포함해야한다

그러면 localhost:3000/news/ 뒤에 어떤 경로가 와도 [newsId].tsx 컴포넌트가 렌더링 될 것이다

이번에는 동적 페이지의 매개변수를 추출해보자.

useRouter훅을 사용해서 매개변수를 추출할 수 있다.

  • pages/news/[newsId].tsx

import type { NextPage } from 'next'
import { useRouter } from 'next/router';

const Detail: NextPage = () => {
  const router = useRouter();
  const newsId = router.query.newsId;
  return (
    <>
      <h1>Detail Page</h1>
      <p>{newsId}</p>
    </>
  );
};

export default Detail;

Catch-All 라우트 추가하기

Catch-All 라우트를 사용하면 어떤 경로이며 얼마나 많은 세그먼트를 갖는지에 상관없이 항상 동일한 컴포넌트를 불러올 수 있다

방법은 간단하다.
자바스크립트의 spread operator처럼 파일 이름을 [...파일명].tsx로 지으면 된다.

  • pages/blog/[...slug].tsx

import { useRouter } from 'next/router';
import React from 'react';

const BlogPostsPage = () => {
  const router = useRouter();
  console.log(router.query);
  return (
    <div>
      <h1>The Blog Posts</h1>
    </div>
  );
};

export default BlogPostsPage;

브라우저에서 localhost:3000/blog/2022/7/18을 입력하고 콘솔을 확인해보자


페이지간 연결하기

마지막으로 페이지 간 연결하기를 해보자.

  • pages/news/index.tsx

import type { NextPage } from 'next'

const News: NextPage = () => {
  return (
    <>
      <h1>News Page</h1>
      <ul>
        <li><a href="/news/first-news">first-news</a></li>
        <li><a href="/news/second-news">second-news</a></li>
      </ul>
    </>
  );
};

export default News;

a태그를 사용해서 페이지 라우팅을 해보았는데 문제점이 있다.
바로 a태그를 사용하면 페이지를 reload시킨다.
a태그는 새로운 HTML파일을 요청하기 때문에 새로고침이 발생한다.

이러면 저장했던 상태들이 전부 사라질 수 있다.
페이지를 새로 불러들였기 때문에 리덕스 상태나 컨텍스트 상태 등 전부 없어질 것이다.

SPA를 유지하기 위해 a태그가 아닌 Link태그를 사용해보자.

기존 react-router에서도 SPA특징을 살리기 위해 Link태그를 사용했는데요, NextJS에서는 react-router가 아닌 next/link에서 기본으로 제공한다.

그리고 Link태그의 프로퍼티로 기존 리액트처럼 to를 사용하지 않고 그대로 href를 사용한다.

  • pages/news/index.tsx

import type { NextPage } from 'next'
import Link from 'next/link';

const News: NextPage = () => {
  return (
    <>
      <h1>News Page</h1>
      <ul>
        <li><Link href="/news/first-news">first-news</Link></li>
        <li><Link href="/news/second-news">second-news</Link></li>
      </ul>
    </>
  );
};

export default News;

위 방법 대신 뉴스 페이지에 대한 데이터를 서버에서 받아왔다는 가정하에 동적으로 링크를 생성할 수 있다.

  • pages/news/index.tsx

import type { NextPage } from "next";
import Link from "next/link";

const News: NextPage = () => {
  const newsPage = [
    { id: "first-news", name: "First News" },
    { id: "second-news", name: "Second News" },
  ];
  return (
    <>
      <h1>News Page</h1>
      <ul>
        {newsPage.map((page) => (
          <li key={page.id}>
            <Link
              href={{ pathname: "/news/[newsId]", query: { newsId: page.id } }}
            >
              {page.name}
            </Link>
          </li>
        ))}
      </ul>
    </>
  );
};

export default News;

이제 페이지를 새로고침 하지 않고 즉각적으로 두 번째 페이지로 이동하는 것을 볼 수 있다.

router.push

  • pages/news/[newsId].tsx

import type { NextPage } from 'next'
import { useRouter } from 'next/router';

const Detail: NextPage = () => {
  const router = useRouter();
  const newsId = router.query.newsId;
  const onPageLoadHandler = () => {
    router.push("/news");
  };
  return (
    <>
      <h1>Detail Page</h1>
      <p>{newsId}</p>
	  <button onClick={onPageLoadHandler}>Go To News Page</button>
    </>
  );
};

export default Detail;

useRouter 객체의 push 메소드를 사용해서 페이지 이동을 트리거 할 수 있다.


커스텀 404에러 페이지 추가하기

pages 폴더에 404.tsx를 추가하면 커스텀 404 페이지를 만들 수 있다.
파일 이름은 꼭 404로 작성해야 한다

  • pages/404.tsx

import React from "react";

const NotFoundPage = () => {
  return (
    <div>
      <h1>Page not found!</h1>
    </div>
  );
};

export default NotFoundPage;

profile
FE Developer

0개의 댓글