Contents
see List개요
Next.js 15는 App Router를 정식 출시하며 React Server Components를 기반으로 한 새로운 렌더링 패러다임을 제공합니다. 이 가이드에서는 App Router의 핵심 개념부터 실전 활용법까지 상세히 다룹니다.
핵심 개념
App Router는 app 디렉토리를 기반으로 하며, 파일 시스템 기반 라우팅을 제공합니다. 주요 특징은 다음과 같습니다:
- 서버 컴포넌트 우선: 기본적으로 모든 컴포넌트는 서버에서 렌더링됩니다.
- 레이아웃 시스템: 중첩된 레이아웃으로 공통 UI를 재사용할 수 있습니다.
- 스트리밍 SSR: Suspense 경계를 활용한 점진적 렌더링이 가능합니다.
- 데이터 페칭: 서버 컴포넌트에서 직접 async/await를 사용할 수 있습니다.
파일 구조와 라우팅
App Router는 특별한 파일명 규칙을 따릅니다:
app/
layout.tsx # 루트 레이아웃
page.tsx # 홈페이지
loading.tsx # 로딩 UI
error.tsx # 에러 UI
blog/
page.tsx # /blog 페이지
[slug]/
page.tsx # /blog/:slug 동적 라우트
(auth)/ # 라우트 그룹 (URL에 포함 안 됨)
login/
page.tsx # /login
서버 컴포넌트 활용
서버 컴포넌트에서는 직접 데이터베이스에 접근할 수 있습니다:
// app/blog/page.tsx
import { db } from '@/lib/db';
export default async function BlogPage() {
const posts = await db.post.findMany({
orderBy: { createdAt: 'desc' },
take: 10,
});
return (
<div>
<h1>블로그</h1>
{posts.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))}
</div>
);
}
클라이언트 컴포넌트와 상호작용
클라이언트 인터랙션이 필요한 경우 'use client' 지시자를 사용합니다:
'use client';
import { useState } from 'react';
export function LikeButton({ postId }: { postId: string }) {
const [likes, setLikes] = useState(0);
const handleLike = async () => {
const res = await fetch(`/api/posts/${postId}/like`, {
method: 'POST',
});
const data = await res.json();
setLikes(data.likes);
};
return (
<button onClick={handleLike}>
좋아요 {likes}
</button>
);
}
데이터 페칭 패턴
Next.js 15는 향상된 캐싱 전략을 제공합니다:
// 기본: fetch 결과는 자동으로 캐시됨
const data = await fetch('https://api.example.com/posts');
// 재검증 주기 설정
const data = await fetch('https://api.example.com/posts', {
next: { revalidate: 3600 } // 1시간마다 재검증
});
// 캐시 사용 안 함 (항상 최신 데이터)
const data = await fetch('https://api.example.com/posts', {
cache: 'no-store'
});
스트리밍과 Suspense
대용량 데이터를 효율적으로 로드하기 위해 스트리밍을 활용합니다:
import { Suspense } from 'react';
async function Posts() {
const posts = await fetchPosts(); // 느린 쿼리
return <PostList posts={posts} />;
}
export default function Page() {
return (
<div>
<h1>블로그</h1>
<Suspense fallback={<PostsSkeleton />}>
<Posts />
</Suspense>
</div>
);
}
메타데이터 관리
SEO를 위한 메타데이터는 정적 또는 동적으로 생성할 수 있습니다:
// 정적 메타데이터
export const metadata = {
title: '블로그',
description: '기술 블로그입니다',
};
// 동적 메타데이터
export async function generateMetadata({ params }) {
const post = await fetchPost(params.slug);
return {
title: post.title,
description: post.excerpt,
openGraph: {
images: [post.coverImage],
},
};
}
활용 팁
- 서버 컴포넌트에서 최대한 많은 로직을 처리하여 클라이언트 번들 크기를 최소화하세요.
- 레이아웃을 활용하여 공통 UI와 상태를 효율적으로 관리하세요.
- 병렬 라우트와 인터셉트 라우트를 사용하면 모달과 같은 고급 UI를 구현할 수 있습니다.
- 서버 액션을 활용하면 API 라우트 없이도 폼 제출을 처리할 수 있습니다.
- React.cache()를 사용하여 동일한 요청의 중복을 방지하세요.
마무리
Next.js 15 App Router는 React의 최신 기능을 최대한 활용하여 성능과 개발 경험을 모두 향상시켰습니다. 서버 컴포넌트와 스트리밍을 적절히 활용하면 빠르고 효율적인 웹 애플리케이션을 구축할 수 있습니다.