1. app 디렉토리
app 디렉토리가 라우팅의 핵심이며 하위 디렉토리 이름을 통해 라우팅을 합니다.
- app 디렉토리가 안보여요!
아직 베타버전이기 때문에 프로젝트 초기 생성시 app 디렉토리가 자동으로 생성되지 않습니다.
대신 이전 버전에 사용했던 pages 폴더가 존재하는데요. 이 pages 폴더를 삭제해주기고 app 디렉토리를 만들어주시면 됩니다.
그리고 app 디렉토리 기능을 켜기 위해 아래와 같이 next.config.js 파일에 다음을 추가합니다.
/** @type {import('next').NextConfig} */
const nextConfig = {
..
experimental: {
appDir: true,
},
..
}
module.exports = nextConfig
2. 파일 컨벤션
특정 디렉토리 내에는 여러가지 약속된 이름을 가진 파일들을 생성할 수 있습니다.
- page.tsx
- layout.tsx
- loading.tsx
- error.tsx
가장 중요하게 알아야할 파일은 page, layout 파일입니다.
page 파일은 라우트 시 보여지게 될 컴포넌트를 정의하게 됩니다.
// `app/page.js` is the UI for the root `/` URL
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
layout 파일은 말그대로 해당 페이지에 적용될 레이아웃을 지정하는 파일입니다.
아래는 app 디렉토리 하위에 있는 루트 레이아웃의 예시입니다.
// app/layout.tsx
export default function RootLayout({ children }: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
- 참고로 app 디렉토리의 Root layout은 필수로 만들어줘야하며, <html>과 <body>를 포함해야한다고 합니다.
- 그 하위 디렉토리부터는 선택적으로 layout.tsx 파일을 만들어주면 됩니다. 만약 없다면 최상단의 root layout만 적용이 되겠죠.
Layout은 중첩 기능을 자동으로 제공합니다.
app/layout.js 가 app/dashboard/layout.js 을 감싸게 됩니다.
화면에는 이 두 레이아웃이 중첩 적용되어 나타나게 되겠죠.
3. 다양한 라우팅 정의 방법
위에서 말씀드렸던 것처럼 기본적으로 디렉토리 이름을 통해 라우팅을 정의할 수 있습니다.
app/shop/page.tsx 는 /shop url와 매칭됩니다.
Url path에 영향을 주지 않으면서 Group화를 하려면 괄호를 디렉토리 이름에 사용하면 됩니다.
아래와 같이 디렉토리를 구성하면 최상단의 layout을 공유하면서도 각 그룹에 따라 다른 layout을 적용할 수 있습니다.
폴더 이름에 대괄호를 활용하면 다이나믹 세그먼트를 생성할 수 있습니다.
예를 들어 app/blog/[slug]/page.js와 같이 디렉토리를 구성하게 되면,
[slug]는 blog의 다이나믹 세그먼트가 됩니다.
Route | Example URL | params |
app/blog/[slug]/page.js | /blog/a | { slug: 'a' } |
app/blog/[slug]/page.js | /blog/b | { slug: 'b' } |
app/blog/[slug]/page.js | /blog/c | { slug: 'c' } |
export default function Page({
params,
}: {
params: { slug: string };
}) {
return <h1>My Page</h1>;
}
- CatchAll segments
Route | Example URL | params |
app/shop/[...slug]/page.js | /shop/a | { slug: ['a'] } |
app/shop/[...slug]/page.js | /shop/a/b | { slug: ['a', 'b'] } |
app/shop/[...slug]/page.js | /shop/a/b/c | { slug: ['a', 'b', 'c'] } |
• Optional CatchAll segments
Route | Example URL | params |
app/shop/[[...slug]]/page.js | /shop | {} |
app/shop/[[...slug]]/page.js | /shop/a | { slug: ['a'] } |
app/shop/[[...slug]]/page.js | /shop/a/b | { slug: ['a', 'b'] } |
app/shop/[[...slug]]/page.js | /shop/a/b/c | { slug: ['a', 'b', 'c'] } |
4. 서버중심 라우팅과 클라이언트사이드 네이게이션
이 4번 챕터는 성능 관련 얘긴데 조금 알쏭달쏭할 수 있습니다.(저도 아직 완벽한 이해는 못했기에..)
부담없이 읽고 5번 챕터로 넘어가도 될 듯합니다.
app 디렉토리는 서버중심 라우팅 방식을 사용합니다.
서버중심 라우팅 방식에서는 클라이언트가 라우트 맵을 다운로드할 필요가 없으며 서버 컴포넌트로 요청을 보내 라우트를 조회합니다.
이렇게 라우팅 자체는 서버쪽에서 이루어지지만, 라우터는 여전히 클라이언트 사이드 네비게이션을 사용합니다.
- 헷갈려요! 라우팅과 네비게이션은 뭐가 다르죠?
라우팅은 웹 애플리케이션의 URL 경로와 컴포넌트 또는 페이지를 **연결**하는 역할을 하고,
네비게이션은 사용자가 웹 애플리케이션에서 다른 페이지로 **이동**하는 것을 관리하는 역할을 합니다
- 어려워요! 서버중심 네비게이션과 클라이언트중심 네비게이션은 뭐가 다른데요?
서버 중심의 네비게이션은 전통적인 웹 애플리케이션의 동작 방식과 유사하며,
사용자가 새로운 페이지로 이동할 때마다 서버에서 새로운 HTML을 렌더링하여
전체 페이지를 새로고침하는 방식으로 동작합니다.
이렇게 서버에서 페이지를 렌더링하는 방식은 검색 엔진 최적화(SEO)에 유리하다는 장점이 있지만,
페이지 이동에 대한 응답 시간이 상대적으로 길어질 수 있고,
전체 페이지를 새로고침하므로 사용자 경험에 대한 부분적인 저하가 발생할 수 있습니다.
반면에 클라이언트 측 네비게이션(Client-Side Navigation)은
SPA(Single Page Application)에서 주로 사용되는 방식으로,
서버에서는 초기 페이지를 렌더링한 후에는 페이지 간의 이동이
브라우저에서 자바스크립트 코드를 사용하여 처리되는 방식입니다.
클라이언트 측 네비게이션은 페이지 간의 전환 시에 전체 페이지를 새로고침하지 않고,
필요한 데이터만 서버로부터 가져와서 화면을 업데이트하는 방식으로 이루어지므로,
사용자 경험이 더 부드럽고 빠른 것이 특징입니다.
즉, Url 경로와 페이지가 연결된 테이블인 라우팅 맵을 가지고 있는 곳은 서버쪽이지만,
그렇다고 서버쪽에서 화면 전환 시마다 전체 HTML을 다시 전달해주지는 않습니다.
브라우저는 전체 HTML을 다시 로드하는 대신 변경된 컴포넌트만을 렌더링합니다. 마치 SPA처럼요.
5. 라우팅 방법
- <Link> 사용법
Next.js에서는 Link 컴포넌트를 통해 prefetching 기능을 지원하여 성능을 높입니다.
말그대로 해당 페이지 방문전에 백그라운드에서 미리 라우트를 로딩하는 것입니다.
이는 클라이언트쪽 캐시에 저장됩니다.
예시
import Link from 'next/link';
export default function PostList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>
{post.title}
</Link>
</li>
))}
</ul>
);
}
예시2
<Link
href="/"
style={{ textDecoration: "none" }}>
<Typography
noWrap
variant="h5"
sx={{
fontFamily: 'monospace',
fontWeight: 700,
color: theme.palette.primary.light,
ml: 0.5,
}}>
NEXTJS
</Typography>
</Link>
- useRouter() 사용법
useRouter()는 클라이언트 컴포넌트에서 라우팅할 수 있는 방법입니다.
'use client';
import { useRouter } from 'next/navigation';
export default function Page() {
const router = useRouter();
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
);
}
참고자료
댓글