본문 바로가기
C.W.K.
Stream
Lesson 05 of 08 · published

App Router가 강한 이유

~22 min · RSC, streaming, Suspense

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

새 폴더가 아니라 새 실행 모델이야

App Router는 React Server Components, Suspense, 스트리밍을 한 덩어리로 설계했어. 그래서 화면을 먼저 완성한 뒤 보내는 대신, 서버와 브라우저가 각자 잘하는 일을 나누고 준비된 부분부터 전달할 수 있어.

  1. 서버 컴포넌트가 기본값이야. 브라우저에 보낼 필요 없는 라이브러리와 데이터 처리를 서버에 남겨.
  2. 중첩 레이아웃이 유지돼. 자식 페이지가 바뀌어도 공통 셸과 그 상태는 살아 있어.
  3. 느린 부분만 기다려. Suspense 경계마다 독립적으로 준비하고 스트리밍해.
  4. 여러 슬롯을 함께 그려. 각 슬롯이 자기 로딩과 오류 경계를 가질 수 있어.
  5. 변경 작업을 서버 함수로 표현해. 내부 CRUD마다 공개 API 주소를 새로 만들 필요가 없어.

클라이언트 JavaScript는 예산이야

상태와 이벤트가 필요한 작은 컴포넌트만 클라이언트로 보내고, 나머지는 서버에 두는 게 기본 자세야. “전부 브라우저에서 돌린 뒤 조금 줄이자”가 아니라 “필요한 부분만 브라우저에 보내자”로 출발점이 뒤집혀.

App Router를 쓰면서 옛 습관을 유지하면

모든 데이터를 페이지 꼭대기에서 읽고, 모든 컴포넌트에 'use client'를 붙이고, 변경마다 API 라우트를 만들면 새 구조의 비용만 내고 이점은 못 받아. 폴더를 옮기는 것보다 책임을 다시 배치하는 일이 먼저야.

화면 트리를 그린 뒤 상태·이벤트·브라우저 API가 필요한 노드에만 표시해 봐. 그 표시가 없는 조상과 형제는 서버에 남길 수 있어. 느린 데이터는 하나의 페이지 loading으로 덮기보다 사용자가 먼저 이해할 수 있는 덩어리마다 Suspense 경계를 두고, 공통 셸은 레이아웃에서 유지해.

서버 컴포넌트가 많다고 무조건 빠른 건 아니야. 서버에서 거대한 데이터를 읽고 직렬화해 클라이언트에 넘기거나, 작은 요청을 순차로 기다리면 다른 병목이 생겨. 핵심은 실행 위치를 숭배하는 게 아니라 전송량·왕복·상호작용의 주인을 가장 싼 곳에 배치하는 거야. 브라우저의 JavaScript를 끄거나 느리게 한 뒤 공통 셸이 언제 보이고 어떤 잎이 상호작용을 잃는지 관찰해. bundle analyzer에서는 use client 경계 하나를 위아래로 옮겨 전송량이 얼마나 달라지는지 재면 경계 위치가 단순 취향이 아니라는 걸 확인할 수 있어.

Code

하위 탐색 뒤에도 살아남는 중첩 레이아웃·tsx
// app/dashboard/layout.tsx
export default function DashboardLayout({
  children,
  analytics,
}: {
  children: React.ReactNode;
  analytics: React.ReactNode; // 병렬 슬롯 @analytics
}) {
  return (
    <div className="grid grid-cols-[240px_1fr_320px]">
      <Sidebar />
      <main>{children}</main>
      <aside>{analytics}</aside>
    </div>
  );
}

// app/dashboard/loading.tsx
export default function Loading() {
  return <DashboardSkeleton />;
}
명시적 Suspense 경계로 스트리밍하기·tsx
import { Suspense } from 'react';

export default function Page() {
  return (
    <>
      <Header /> {/* 빠름, 서버에서 렌더링된 */}
      <Suspense fallback={<StatsSkeleton />}>
        <Stats />        {/* 느린 질의, 스트리밍 */}
      </Suspense>
      <Suspense fallback={<ChartSkeleton />}>
        <RevenueChart /> {/* 독립 스트리밍 */}
      </Suspense>
    </>
  );
}

External links

Exercise

데이터가 느린 라우트에 loading.tsx를 추가하고 느린 잎을 Suspense로 감싸. 변경 전후에 사용자가 첫 화면과 완성된 내용을 보는 시점을 기록해.

Progress

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

댓글 0

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

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