
사용자 경험(UX)을 크게 좌우하는 요소 중 하나는 로딩 상태와 에러 처리 UI이다.
특히 Next.js(App Router)에서는 이를 파일 단위로 구조화하여 매우 직관적으로 관리할 수 있다.
처음에는 단순한 보조 UI라고 생각했지만, 직접 적용해보면서
Streaming만으로는 UX가 완성되지 않고, fallback UI 설계가 반드시 필요하다는 점을 체감하게 되었다.
이 글에서는 다음 내용을 정리한다.
loading.tsxerror.tsxnot-found.tsxloading.tsx는 해당 라우트(segment)가 로딩 중일 때 자동으로 보여지는 UI이다.
즉, 데이터 fetching 또는 서버 컴포넌트가 아직 준비되지 않았을 때
사용자에게 보여줄 fallback UI를 정의하는 역할을 한다.
// app/posts/loading.tsx
export default function Loading() {
return <p>Loading posts...</p>;
}
👉 실제로 적용해보니 단순 텍스트보다 Skeleton UI가 훨씬 자연스럽게 느껴졌다.
error.tsx는 해당 라우트에서 에러 발생 시 보여주는 UI이다.
React의 Error Boundary 기반으로 동작하며,
예상치 못한 에러 상황에서도 UI를 유지할 수 있게 해준다.
'use client')reset() 함수를 통해 에러 복구 가능'use client';
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return (
<div>
<h2>Something went wrong!</h2>
<button onClick={() => reset()}>Try again</button>
</div>
);
}
👉 단순히 에러를 보여주는 것보다, 다시 시도할 수 있게 만드는 게 훨씬 중요하다고 느꼈다.
not-found.tsx는 존재하지 않는 경로이거나
notFound()가 호출될 때 보여지는 UI이다.
// app/posts/not-found.tsx
export default function NotFound() {
return <h2>Post Not Found</h2>;
}
// 사용 예시
import { notFound } from 'next/navigation';
export default async function Page({ params }) {
const data = await fetchData(params.id);
if (!data) {
notFound();
}
return <div>{data.title}</div>;
}
👉 기존에는 전역 404만 생각했는데, 이렇게 나눌 수 있다는 점이 인상적이었다.
React의 Suspense를 활용하면
컴포넌트 단위로 로딩 상태를 제어할 수 있다.
import { Suspense } from 'react';
import PostList from './PostList';
export default function Page() {
return (
<Suspense fallback={<p>Loading posts...</p>}>
<PostList />
</Suspense>
);
}
👉 loading.tsx만으로는 부족하고, Suspense를 같이 써야 세밀한 제어가 가능했다.
서버에서 데이터를 모두 준비한 후 보내는 것이 아니라,
준비된 UI부터 점진적으로 클라이언트에 전달하는 방식이다.
Streaming을 적용하면 페이지가 빠르게 보이긴 했지만,
실제로는 UX가 완전히 좋아졌다고 느껴지지는 않았다.
특히 아래와 같은 상황이 있었다.
👉 Streaming만으로는 부족하고,
👉 반드시 fallback UI와 같이 설계해야 한다.
즉,
loading.tsxSuspense fallback이 둘이 함께 있어야 자연스러운 UX가 만들어진다.
[사용자 요청]
↓
[Streaming 시작]
↓
[Fallback UI 먼저 렌더링]
↓
[데이터 준비 완료]
↓
[실제 UI로 점진적 교체]
loading.tsx → 자동 fallback UIerror.tsx → Error Boundarynot-found.tsx → 라우트 단위 404 처리Streaming은 빠르게 보여주기 위한 것이고,
실제 사용자 경험은 fallback UI가 완성한다.
이번 내용을 정리하면서 느낀 점은,
로딩과 에러 처리는 단순히 "예외 상황 처리"가 아니라
사용자 흐름을 끊지 않기 위한 설계 요소라는 것이다.
Next.js App Router는 이런 부분을 구조적으로 나눌 수 있게 해주기 때문에,
기능 구현뿐 아니라 UX까지 같이 고민하게 만드는 도구라고 느꼈다.