React 18 useDeferredValue 심화: 검색 자동완성에서 디바운싱을 제거하는 이유

React 18 useDeferredValue 심화: 검색 자동완성에서 디바운싱을 제거하는 이유

Next.js 13+ 로딩 마스터: loading.js와 Suspense의 관계 완벽 정리

Next.js 13+ 로딩 마스터: loading.js와 Suspense의 관계 완벽 정리

Server Components(RSC) 시대로의 전환, 'Instant Loading'을 이해하는 법

Next.js Pages Router에서 App Router로 넘어오면서 가장 체감되는 변화 중 하나는 바로 데이터 페칭과 로딩 처리 방식입니다.
과거에는 `useEffect` 안에서 데이터를 가져오고 `isLoading` 상태를 직접 관리했다면, 이제는 파일 시스템 하나로 우아한 처리가 가능해졌습니다.

❓ 의문점
"그냥 `loading.js` 파일을 만들면 로딩 화면이 뜬다던데, 도대체 무슨 원리일까?"
"내가 직접 쓰는 `` 컴포넌트랑은 무엇이 다를까?"

이 글에서는 Next.js가 loading.js를 어떻게 처리하는지, 그리고 이것이 React Suspense와 어떤 관계인지 명확히 짚어드리겠습니다.
서버 사이드 렌더링의 핵심인 스트리밍(Streaming) 기술을 이해하면, 여러분의 웹사이트 속도는 체감상 2배 더 빨라질 것입니다.


📂 1. loading.js는 사실 '자동화된 Suspense'다

결론부터 말씀드리면, Next.js의 loading.js는 마법이 아닙니다.
빌드 타임에 Next.js는 `loading.js` 파일이 존재하면, 해당 경로의 `page.js`를 자동으로 React Suspense 컴포넌트로 감싸버립니다.

🖥️ 우리가 작성한 파일 구조

  • app/
  • ├── dashboard/
  • │   ├── loading.js
  • │   └── page.js

⚙️ Next.js가 변환한 실제 코드 형태

<Layout>
  <Header />
  <SideNav />
  <Suspense fallback={<Loading />}>
    <Page />
  </Suspense>
</Layout>

즉, `loading.js`는 페이지 전체(혹은 해당 레이아웃 하위 세그먼트)에 대한 "즉시 로딩 상태(Instant Loading State)"를 정의하는 파일 시스템 규칙일 뿐입니다.
이 덕분에 서버 컴포넌트가 데이터를 다 가져올 때까지 브라우저가 하얀 화면으로 멈춰있는 것을 방지할 수 있습니다.


🌊 2. 서버 사이드 스트리밍(Streaming)의 마법

기존의 SSR(Server-Side Rendering)은 데이터가 준비될 때까지 HTML을 전혀 보내지 못하는 'Waterfalls' 문제가 있었습니다.
하지만 `loading.js`와 `Suspense`를 활용한 RSC 아키텍처는 HTML을 조각조각 나누어 스트리밍합니다.

🚀 스트리밍 처리 순서

  1. 1단계 (즉시 전송): 서버는 요청 즉시, 레이아웃(`layout.js`)과 로딩 UI(`loading.js`)가 포함된 HTML 껍데기를 먼저 브라우저로 보냅니다.
  2. 2단계 (데이터 대기): 서버에서 `page.js` 내부의 비동기 함수(`await fetchData()`)가 실행되는 동안, 사용자는 스켈레톤 UI를 보고 있습니다.
  3. 3단계 (치환): 데이터 로딩이 완료되면, 서버는 나머지 HTML 조각과 데이터를 전송하고, React는 스켈레톤을 실제 콘텐츠로 Swap합니다.

이 과정은 브라우저가 페이지를 새로고침 하지 않아도 자연스럽게 일어납니다.
이것이 바로 Next.js 13+가 제공하는 TTFB(Time To First Byte)FCP(First Contentful Paint) 최적화의 핵심입니다.


⚖️ 3. 언제 loading.js를 쓰고, 언제 Suspense를 쓸까?

`loading.js`는 페이지 단위의 큰 로딩을 처리하기엔 좋지만, 페이지 내부의 일부분만 로딩하고 싶을 때는 적합하지 않을 수 있습니다.
이때는 우리가 직접 ``를 사용하여 로딩 단위를 쪼개는(Granular Control) 전략이 필요합니다.

구분 loading.js (파일 기반) <Suspense> (직접 사용)
적용 범위 페이지 전체 (Page Segment) 컴포넌트 단위 (Component Level)
장점 구현이 매우 쉽고 자동화됨 필요한 부분만 로딩시켜 UX 최적화
추천 상황 초기 진입 시 전체 레이아웃 로딩 무거운 차트, 댓글 목록 등 일부 섹션
// page.js 내부
export default function Dashboard() {
  return (
    <>
      <h1>대시보드</h1>
      
      {/* 느린 컴포넌트만 별도로 로딩 처리 */}
      <Suspense fallback={<SkeletonChart />}>
        <RevenueChart />
      </Suspense>
      
      <RecentActivity />
    </>
  );
}

위 코드처럼 작성하면, `RevenueChart`가 데이터를 불러오는 동안에도 사용자는 `RecentActivity` 같은 다른 컴포넌트를 즉시 볼 수 있습니다. 이것이 병렬 데이터 페칭(Parallel Data Fetching)의 이점입니다.


✨ 요약 및 마무리

Next.js 13+의 로딩 시스템은 개발자에게는 편리함(loading.js)을, 사용자에게는 속도(Streaming)를 제공하는 강력한 도구입니다.
이제 더 이상 데이터를 기다리며 빈 화면을 보여주지 마세요.

📝 핵심 포인트 3줄 요약

  • loading.js는 `page.js`를 감싸는 자동화된 Suspense Boundary다.
  • 서버는 HTML 스트리밍을 통해 껍데기(UI)를 먼저 보내고, 알맹이(Data)를 나중에 채워 넣는다.
  • 페이지 전체 로딩은 loading.js, 부분 로딩 최적화는 Manual Suspense를 사용해라.

댓글 쓰기