폴더를 만들면 주소가 생긴다
Article
React로 여러 페이지를 만들려면 라우팅 라이브러리를 깔고 설정을 써야 했다.
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/products/:id" element={<Product />} />
</Routes>
Next.js에는 이런 파일이 없다. 폴더를 만들면 그게 주소다.
프로젝트를 만든다
npx create-next-app@latest my-app
몇 가지를 묻는다. 지금은 이렇게 답한다.
| 질문 | 선택 | 이유 |
|---|---|---|
| TypeScript? | No | Next.js 를 먼저 익힌다 |
| ESLint? | Yes | 실수를 잡아준다 |
| Tailwind CSS? | 취향 | 이 시리즈는 쓰지 않는다 |
| src/ directory? | Yes | 코드와 설정이 섞이지 않는다 |
| App Router? | Yes | 필수. 이 시리즈의 전제다 |
| Turbopack? | Yes | Next 16 의 기본값이다 |
cd my-app
npm run dev
http://localhost:3000을 열면 시작 페이지가 뜬다.
app 폴더가 전부다
만들어진 폴더 중 지금 볼 것은 하나다.
- my-app
- src/app
- layout.js
- page.js
- globals.css
- public
- next.config.ts
- src/app
app/page.js를 열어 통째로 지우고 이렇게 쓴다.
export default function Home() {
return <h1>홈</h1>;
}
React 편에서 만들던 컴포넌트와 똑같다. export default가 필수라는 것만 다르다. Next.js가 이 파일을 찾아 그 함수를 실행하기 때문이다.
1강에서 말한 "내가 부르는가, 불리는가"가 여기서 드러난다. 우리는 <Home />이라고 쓴 적이 없다.
폴더가 주소다
app/about/page.js를 만든다.
export default function About() {
return <h1>소개</h1>;
}
/about으로 가면 이 화면이 뜬다. 설정 파일을 고치지 않았다.
- app/루트
- products//products
- shoes//products/shoes
- page.js이 파일이 화면
몇 개 더 만들어보면 규칙이 보인다.
| 파일 | 주소 |
|---|---|
| app/page.js | / |
| app/about/page.js | /about |
| app/blog/page.js | /blog |
| app/blog/first-post/page.js | /blog/first-post |
| app/products/shoes/page.js | /products/shoes |
폴더는 주소를 만들고, page.js가 화면을 만든다.
폴더만으로는 주소가 안 생긴다
여기가 헷갈리는 지점이다.
- app
- dashboard
- settings
- dashboard
/dashboard는 404다. 폴더는 있지만 그 주소에 보여줄 화면이 없기 때문이다. /dashboard/settings는 잘 뜬다.
이걸 이용해 주소를 만들지 않는 폴더를 둘 수 있다. 컴포넌트나 유틸을 app 안에 두어도 라우트가 되지 않는다.
특수한 파일 이름들
page.js 말고도 Next.js가 알아보는 이름이 몇 개 있다. 정해진 이름을 정해진 자리에 두면 Next.js가 알아서 쓴다.
| 파일명 | 역할 | 언제 보이나 |
|---|---|---|
| page.js | 그 주소의 화면 | 항상 |
| layout.js | 감싸는 껍데기 | 항상 |
| loading.js | 로딩 중 화면 | 데이터를 기다릴 때 |
| error.js | 에러 화면 | 예외가 터졌을 때 |
| not-found.js | 404 화면 | 없는 주소일 때 |
4강에서 하나씩 다룬다. 지금은 파일 이름이 곧 약속이라는 것만 기억한다.
Page.js나 pages.js는 동작하지 않는다. 대소문자와 철자가 정확해야 한다.
layout.js — 모든 페이지를 감싼다
app/layout.js를 열어본다.
export default function RootLayout({ children }) {
return (
<html lang="ko">
<body>{children}</body>
</html>
);
}
children이 보인다. React 편 6강에서 배운 그것이다.
children 자리에 각 페이지가 들어온다. /about으로 가면 About 컴포넌트가, /blog로 가면 Blog가 그 자리에 꽂힌다.
- layout.jshtml · body · 헤더
- {children}여기에
- page.js페이지가 들어온다
그래서 헤더와 푸터를 여기 두면 모든 페이지에 나온다.
export default function RootLayout({ children }) {
return (
<html lang="ko">
<body>
<header>로고와 메뉴</header>
<main>{children}</main>
<footer>저작권</footer>
</body>
</html>
);
}
링크로 이동한다
<a> 태그를 쓰면 페이지 전체가 새로고침된다. 자바스크립트 상태가 전부 날아가고 화면이 깜빡인다.
Next.js는 <Link>를 쓴다.
import Link from "next/link";
export default function Header() {
return (
<nav>
<Link href="/">홈</Link>
<Link href="/about">소개</Link>
</nav>
);
}
<a href>
브라우저 기본 이동
- 페이지 전체를 다시 받는다
- 화면이 깜빡인다
- React 상태가 사라진다
<Link href>
클라이언트 네비게이션
- 바뀐 부분만 받는다
- 깜빡이지 않는다
- 레이아웃과 상태가 유지된다
- 화면에 보이면 미리 받아둔다
마지막 항목이 중요하다. <Link>가 화면에 보이면 Next.js가 그 페이지를 미리 내려받는다. 클릭하는 순간 이미 준비돼 있어서 즉시 바뀐다. 이걸 **프리페치(prefetch)**라 부른다.
개발 서버가 알려주는 것
npm run dev를 띄워두고 페이지를 열면 터미널에 로그가 찍힌다.
- ▲ Next.js 16 (Turbopack)
- - Local: http://localhost:3000
- GET / 200 in 45ms (compile 30ms, render 15ms)
Next 16부터 시간이 어디에 쓰였는지 나눠 보여준다. compile은 코드를 준비하는 데, render는 우리 코드를 실행하는 데 걸린 시간이다.
render가 유난히 길다면 우리 코드가 느린 것이다. 나중에 데이터를 받아올 때 이 숫자를 보게 된다.
정리하면
- Next.js에는 라우팅 설정 파일이 없다.
app폴더의 구조가 곧 URL이다. - 폴더가 주소를 만들고,
page.js가 화면을 만든다.page.js가 없으면 그 주소는 404다. - 그래서
app안에 컴포넌트를 둬도 라우트가 되지 않는다. layout.js는 모든 페이지를 감싼다.<html>과<body>가 여기 있고,children자리에 페이지가 들어온다.- 이동은 **
<Link>**로 한다. 바뀐 부분만 받고, 화면에 보이면 미리 받아둔다. - Next 16은 Turbopack이 기본이고,
next lint는 제거됐다.
다음 강의에서는 이 컴포넌트들이 어디서 실행되는지 본다. 브라우저가 아니다.