본문 바로가기
C.W.K.
Stream
Lesson 04 of 10 · published

중첩 레이아웃의 수명 이해하기

~20 min · layout, nesting, template

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

폴더 트리가 그대로 렌더 트리가 돼

각 라우트 구간은 자기 layout.tsx를 가질 수 있고, 자식 레이아웃은 부모 레이아웃 안에 자동으로 들어가. 따로 import해서 껍데기를 조립하지 않아도 폴더 구조가 화면의 감싸기 순서를 결정해.

app/layout.tsx                       → 모든 화면을 감쌈
  app/dashboard/layout.tsx           → /dashboard/*를 감쌈
    app/dashboard/settings/page.tsx  → 두 레이아웃 안에 표시됨

주소가 바뀌어도 같은 조상은 유지돼

/dashboard/settings에서 /dashboard/billing으로 이동하면 두 페이지가 공유하는 루트와 대시보드 레이아웃은 그대로 있고 페이지 부분만 바뀌어. 반대로 /marketing/pricing으로 가면 대시보드 레이아웃은 트리에서 빠지고 마케팅 쪽 레이아웃이 들어와. 어느 상태가 살아남는지는 URL 전체가 아니라 두 라우트가 공유하는 조상이 결정해.

초기 선택은 layout.tsx

대부분의 공통 UI에는 레이아웃이 맞아. 이동할 때마다 상태를 새로 만들거나 진입·퇴장 애니메이션을 처음부터 재생해야 할 때만 template.tsx를 써. 두 파일은 같은 props를 받지만 템플릿은 내비게이션마다 다시 마운트된다는 차이가 있어.

수명부터 정하고 자리를 골라

컴포넌트가 오래 살아야 해서 레이아웃에 놓는 게 아니라, 그 구간 전체가 공유해야 하는 책임이라서 놓는 거야. 공유 범위와 초기화 시점을 먼저 말로 적으면 레이아웃이 비대해지는 일을 막을 수 있어.

두 주소 사이를 이동할 때 어떤 조상이 유지되어야 하는지 렌더 트리로 그려 봐. 대시보드 안의 탭 상태는 대시보드 레이아웃에, 앱 전체 테마는 루트에 두는 식이야. 상태 초기화 버그는 컴포넌트 코드보다 잘못 고른 수명 경계에서 더 자주 생겨. template.tsx로 강제 재마운트하면 오래된 상태 문제를 빨리 숨길 수 있지만, 입력 중인 값과 네트워크 캐시도 함께 버릴 수 있어. 먼저 상태가 잘못된 조상에 있는지 확인하고, 화면 전체가 새 인스턴스여야 한다는 제품 이유가 있을 때만 템플릿을 골라.

/dashboard/settings/dashboard/billing, 그리고 다른 최상위 구역 사이를 이동하며 mount 로그를 남겨. 조상 레이아웃과 template의 mount 횟수를 비교하고, 애니메이션 때문에 template을 썼을 때 사용자가 입력하던 상태까지 사라지는지 확인해 선택의 대가를 보여.

Code

3단계 중첩 구현하기·tsx
// app/layout.tsx — 사이트 공통 UI
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en"><body>
      <SiteNav />
      {children}
    </body></html>
  );
}

// app/(app)/layout.tsx — 앱 공통 화면(라우트 그룹이라 URL에는 /(app)/이 들어가지 않아)
export default function AppLayout({ children }: { children: React.ReactNode }) {
  return <div className="flex"><AppSidebar /><div className="flex-1">{children}</div></div>;
}

// app/(app)/dashboard/layout.tsx — 대시보드 공통 UI
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  return <div className="p-6 space-y-4"><DashboardTabs />{children}</div>;
}

// app/(app)/dashboard/billing/page.tsx — 위 세 레이아웃이 모두 감싸
다시 마운트해야 할 때는 template·tsx
// app/(app)/dashboard/template.tsx — 이동할 때마다 새 인스턴스
'use client';
import { motion } from 'framer-motion';

export default function Template({ children }: { children: React.ReactNode }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 8 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.18 }}
    >
      {children}
    </motion.div>
  );
}

External links

Exercise

대시보드에 세 단계 중첩 레이아웃을 만들고 React DevTools로 가장 깊은 페이지만 바뀔 때 부모 레이아웃이 언마운트되지 않는지 확인해.

Progress

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

댓글 0

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

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