Awaik
/ Blog
List

This post is only available in Korean.

Next.js App Router 완벽 가이드

Next.js 15의 App Router를 사용하여 현대적인 웹 애플리케이션을 구축하는 방법을 알아봅니다.

Awaik
#Next.js#React#개발#튜토리얼

Next.js App Router 완벽 가이드

Next.js 15에서 도입된 App Router는 React Server Components를 기반으로 한 새로운 라우팅 시스템입니다. 이 가이드에서는 App Router의 핵심 개념과 실제 사용 방법을 알아보겠습니다.

App Router vs Pages Router

기존의 Pages Router와 비교했을 때 App Router의 주요 차이점:

특징Pages RouterApp Router
파일 위치pages/app/
라우팅파일 기반폴더 기반
서버 컴포넌트
레이아웃_app.jslayout.tsx
로딩 상태수동 구현loading.tsx

기본 라우트 만들기

App Router에서는 폴더가 URL 경로를 정의합니다:

// app/blog/page.tsx
export default function BlogPage() {
  return <h1>Blog</h1>;
}

위 코드는 /blog 경로에 매핑됩니다.

동적 라우트

대괄호를 사용하여 동적 라우트를 만들 수 있습니다:

// app/blog/[slug]/page.tsx
export default async function BlogPostPage({
  params
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  return <h1>Post: {slug}</h1>;
}

서버 컴포넌트와 클라이언트 컴포넌트

서버 컴포넌트 (기본)

// 기본적으로 모든 컴포넌트는 서버 컴포넌트
async function BlogList() {
  const posts = await fetchPosts();
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

클라이언트 컴포넌트

'use client';

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

레이아웃과 템플릿

레이아웃

레이아웃은 여러 페이지에서 공유되는 UI입니다:

// app/layout.tsx
export default function RootLayout({
  children
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ko">
      <body>
        <nav>내비게이션</nav>
        {children}
        <footer>푸터</footer>
      </body>
    </html>
  );
}

데이터 페칭

서버 컴포넌트에서

async function Posts() {
  const res = await fetch('https://api.example.com/posts', {
    cache: 'no-store' // 캐시 없이 항상 최신 데이터
  });
  const posts = await res.json();
  return <PostList posts={posts} />;
}

병렬 데이터 페칭

async function Page() {
  const [posts, comments] = await Promise.all([
    fetchPosts(),
    fetchComments()
  ]);

  return (
    <>
      <Posts data={posts} />
      <Comments data={comments} />
    </>
  );
}

스트리밍과 Suspense

import { Suspense } from 'react';

export default function Page() {
  return (
    <>
      <Header />
      <Suspense fallback={<PostsLoading />}>
        <Posts />
      </Suspense>
      <Suspense fallback={<CommentsLoading />}>
        <Comments />
      </Suspense>
    </>
  );
}

메타데이터

정적 메타데이터

import type { Metadata } from "next";

export const metadata: Metadata = {
  title: "블로그",
  description: "개발 블로그입니다",
};

동적 메타데이터

export async function generateMetadata({
  params,
}: {
  params: Promise<{ slug: string }>;
}): Promise<Metadata> {
  const { slug } = await params;
  const post = await getPost(slug);

  return {
    title: post.title,
    description: post.description,
  };
}

에러 핸들링

// app/blog/error.tsx
'use client';

export default function Error({
  error,
  reset
}: {
  error: Error;
  reset: () => void;
}) {
  return (
    <div>
      <h2>문제가 발생했습니다!</h2>
      <button onClick={reset}>다시 시도</button>
    </div>
  );
}

로딩 상태

// app/blog/loading.tsx
export default function Loading() {
  return <div>로딩 중...</div>;
}

결론

App Router는 Next.js의 미래입니다. Server Components와 Suspense를 활용하여 더 나은 사용자 경험과 성능을 제공할 수 있습니다.

핵심 포인트:

  • ✅ 서버 컴포넌트를 기본으로 사용
  • ✅ 클라이언트 컴포넌트는 필요할 때만
  • ✅ Suspense로 점진적 로딩
  • ✅ 병렬 데이터 페칭으로 성능 최적화

더 자세한 내용은 Next.js 공식 문서를 참고하세요!