dev.syw

layout, loading, error, not-found 특수 파일로 화면을 구성한다.

레이아웃·로딩·에러 처리

App Router에는 폴더에 두기만 하면 자동으로 동작하는 특수 파일 들이 있습니다. 공통 레이아웃, 로딩 화면, 에러 화면, 404 화면을 코드 한 줄 연결 없이 만들 수 있습니다. 이번 레슨에서 핵심 네 가지를 익힙니다.

학습 목표

  • layout.tsx 로 공통 UI를 만들고 중첩한다.
  • template.tsx 와 layout의 차이를 안다.
  • loading.tsx 로 Suspense 기반 로딩 화면을 만든다.
  • error.tsxnot-found.tsx 로 오류를 우아하게 처리한다.

layout.tsx — 공통 레이아웃

layout.tsx 는 하위 페이지들을 감싸는 껍데기입니다. 루트 레이아웃은 <html>, <body> 를 포함하며 반드시 있어야 합니다. children 으로 페이지가 들어옵니다.

// app/layout.tsx — 루트 레이아웃
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ko">
      <body>
        <header>사이트 헤더</header>
        {children}
        <footer>© 2026</footer>
      </body>
    </html>
  );
}

레이아웃은 중첩됩니다. 폴더마다 layout.tsx 를 두면 바깥 레이아웃 안에 안쪽 레이아웃이 끼워집니다.

app/
├── layout.tsx              →  전체 껍데기
└── dashboard/
    ├── layout.tsx          →  대시보드 전용 사이드바
    └── page.tsx

💡 TIP — 레이아웃은 페이지를 이동해도 다시 렌더되지 않고 상태를 유지합니다. 사이드바의 스크롤 위치가 페이지 전환에도 보존되는 이유입니다.

template.tsx — 매번 새로 그리는 껍데기

template.tsx 는 레이아웃과 거의 같지만, 페이지를 이동할 때마다 새 인스턴스로 다시 마운트됩니다. 페이지 전환 애니메이션이나 진입 시마다 초기화가 필요할 때 씁니다.

파일이동 시 동작상태
layout.tsx유지(재렌더 안 함)보존
template.tsx매번 다시 마운트초기화

loading.tsx — 로딩 화면

loading.tsx 를 두면 Next.js가 해당 세그먼트를 자동으로 <Suspense> 로 감쌉니다. 서버 컴포넌트가 데이터를 기다리는 동안 이 화면이 먼저 보입니다.

// app/posts/loading.tsx
export default function Loading() {
  return <p>글을 불러오는 중...</p>;
}

같은 폴더의 page.tsxasync 로 데이터를 기다리면, 그동안 자동으로 loading.tsx 가 표시됩니다. 별도 상태 관리가 필요 없습니다.

error.tsx — 에러 경계

렌더 중 에러가 나면 error.tsx 가 그 자리에 표시됩니다. 에러 경계는 클라이언트 컴포넌트 여야 하므로 'use client' 가 필요합니다.

'use client';

export default function Error({
  error,
  reset,
}: {
  error: Error;
  reset: () => void;
}) {
  return (
    <div>
      <p>문제가 발생했어요: {error.message}</p>
      <button onClick={() => reset()}>다시 시도</button>
    </div>
  );
}

reset 을 호출하면 해당 세그먼트를 다시 렌더링하려 시도합니다.

⚠️ 주의error.tsx 는 같은 세그먼트의 layout.tsx 에서 난 에러는 잡지 못합니다. 그 경우 한 단계 위(상위 폴더)의 error.tsx 가 처리합니다.

not-found.tsx — 404 화면

notFound() 함수를 호출하면 가장 가까운 not-found.tsx 가 렌더됩니다. 데이터가 없을 때 깔끔하게 404를 보여줄 수 있습니다.

// app/blog/[slug]/page.tsx
import { notFound } from 'next/navigation';

export default async function Post({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  const post = await getPost(slug);
  if (!post) notFound(); // → not-found.tsx 렌더
  return <article>{post.title}</article>;
}
// app/blog/[slug]/not-found.tsx
export default function NotFound() {
  return <p>찾는 글이 없어요.</p>;
}

요약

  • layout.tsx 는 중첩되는 공통 껍데기이며 이동해도 상태를 유지한다.
  • template.tsx 는 이동마다 다시 마운트되는 껍데기다.
  • loading.tsx 는 자동 Suspense 로딩 화면을 만든다.
  • error.tsx(클라이언트)와 not-found.tsx 로 오류와 404를 처리한다.

연습문제

  1. /dashboard 에 사이드바가 있는 전용 layout.tsx 를 만들어 보세요.
  2. 데이터를 1초 지연시켜 패칭하는 페이지에 loading.tsx 를 추가하고, 로딩 화면이 보이는지 확인하세요.
  3. 일부러 에러를 던지는 컴포넌트를 만들고 error.tsx 로 잡아 "다시 시도" 버튼을 붙여 보세요.
  4. 존재하지 않는 글 slug일 때 notFound() 를 호출하도록 만들어 보세요.

힌트error.tsx 는 반드시 'use client' 로 시작해야 합니다. loading.tsx 는 같은 폴더의 async page 가 데이터를 기다릴 때만 보입니다.

💡 연습문제 풀이

불러오는 중…

함께 보면 좋은 자료

댓글 0

Next.js” 강좌에 대한 댓글입니다.

댓글을 작성하려면 로그인이 필요합니다.