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에 페이지를 추가해 보자.
import type { NextPage } from 'next'
const Home: NextPage = () => {
return (
<h1>Home Page</h1>
)
}
export default Home
터미널에 npm run dev
명령어를 입력해서 localhost:3000에서 결과를 확인해보자.
이번에는 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를 생성한다.
import type { NextPage } from 'next'
const News: NextPage = () => {
return (
<h1>
News Page
</h1>
);
};
export default News;
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
훅을 사용해서 매개변수를 추출할 수 있다.
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로 지으면 된다.
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
을 입력하고 콘솔을 확인해보자
마지막으로 페이지 간 연결하기를 해보자.
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
를 사용한다.
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;
위 방법 대신 뉴스 페이지에 대한 데이터를 서버에서 받아왔다는 가정하에 동적으로 링크를 생성할 수 있다.
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
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 메소드를 사용해서 페이지 이동을 트리거 할 수 있다.
pages 폴더에 404.tsx
를 추가하면 커스텀 404 페이지를 만들 수 있다.
파일 이름은 꼭 404
로 작성해야 한다
import React from "react";
const NotFoundPage = () => {
return (
<div>
<h1>Page not found!</h1>
</div>
);
};
export default NotFoundPage;