C.W.K.
Stream
Lesson 09 of 10 · published

Loading, Error, Not Found

~22 min · loading, error, not-found, Suspense

Level 0Curious
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

특수 file 셋, behavior 셋

File역할Server or Client?
loading.tsxPage 를 Suspense 로 wrap; data load 동안 보여줌둘 다
error.tsxSegment + 그 아래 error boundaryClient 필수
not-found.tsxSegment 안 notFound() 부르면 UI둘 다

Root 위한 global-error.tsx

error.tsx 는 자기 layout 의 에러 못 잡음. Root layout 한정 특수 boundary: app/global-error.tsx. 자기 render 해야 함 — 깨진 root layout 을 통째로 대체하니까.

아무 데서나 404 trigger

next/navigationnotFound() 를 Server Component 안에서 부르면 가장 가까운 not-found.tsx render 하며 bail out. Status code (404) 는 framework 가 알아서.

Code

Loading skeleton 자동 wiring·tsx
// app/dashboard/loading.tsx
export default function Loading() {
  return (
    <div className="animate-pulse space-y-3 p-6">
      <div className="h-6 w-1/3 rounded bg-gray-200" />
      <div className="h-4 w-full rounded bg-gray-200" />
      <div className="h-4 w-5/6 rounded bg-gray-200" />
    </div>
  );
}

// app/dashboard/page.tsx — 느린 data 가 boundary trigger
export default async function Dashboard() {
  const data = await fetchSlow();
  return <DashboardContent data={data} />;
}
Segment 별 error boundary·tsx
// app/dashboard/error.tsx
'use client';
import { useEffect } from 'react';

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  useEffect(() => {
    // Sentry / 본인 logger 로 ship
    console.error(error);
  }, [error]);

  return (
    <div className="p-6 text-center">
      <h2 className="text-lg font-semibold">Something went wrong</h2>
      <p className="text-sm text-gray-500 mt-1">{error.message}</p>
      <button
        onClick={() => reset()}
        className="mt-4 rounded bg-blue-600 px-4 py-2 text-white"
      >
        Try again
      </button>
    </div>
  );
}
Server Component 안에서 404·tsx
import { notFound } from 'next/navigation';

export default async function Page({
  params,
}: {
  params: Promise<{ id: string }>;
}) {
  const { id } = await params;
  const post = await getPost(id);
  if (!post) notFound();
  return <Article post={post} />;
}

External links

Exercise

Route 에 loading.tsx, error.tsx, not-found.tsx 추가. Page 안에서 에러 throw 하고 boundary 가 잡는지 확인; unknown id 로 notFound() 부르고 not-found UI 가 network tab 에 404 status 와 함께 뜨는지 확인.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.