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

layout.tsx로 공유 UI 유지하기

~20 min · layout, persistence, root layout

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

레이아웃은 하위 라우트를 감싸고 살아남아

layout.tsx는 자신이 놓인 구간과 그 아래의 모든 라우트를 감싸. 같은 레이아웃 아래에서 형제 페이지로 이동해도 레이아웃 컴포넌트는 언마운트되지 않아. 내비게이션, 사이드바, 레이아웃이 가진 로컬 상태를 페이지마다 다시 만들지 않아도 되는 이유야.

루트 레이아웃은 반드시 하나 필요해

모든 App Router 앱에는 app/layout.tsx가 있어야 하고, 여기서 <html><body>를 직접 반환해야 해. 문서 언어, 전역 글꼴, body 클래스처럼 앱 전체가 상속할 설정도 이 자리에 둬. 이 두 태그를 다른 페이지에서 다시 만들면 문서 구조가 깨져.

레이아웃이 받는 값에는 경계가 있어

레이아웃은 하위 페이지나 레이아웃이 들어오는 children을 받아. 동적 구간 안에 있다면 Next.js 15부터 params도 Promise로 오므로 기다려서 읽어야 해. 반면 searchParams는 받지 않아. 레이아웃이 질의 문자열에 따라 달라져야 한다면, 그 데이터를 페이지 안의 서버 컴포넌트에서 읽도록 책임을 옮기는 편이 맞아.

유지가 곧 계약이야

레이아웃에 놓은 상태는 이동 뒤에도 남는다는 전제 아래 설계해야 해. 페이지가 바뀔 때마다 초기화돼야 하는 폼이나 애니메이션을 무심코 넣으면 오래된 상태가 따라다닐 수 있어. 그런 경우에만 다음 레슨의 template.tsx를 검토해.

레이아웃에 넣을 항목마다 두 질문을 해 봐. 하위 모든 페이지가 정말 공유하는가, 형제 페이지를 오갈 때 상태가 남아야 하는가. 두 답이 모두 맞으면 레이아웃 자리야. 검색 입력처럼 페이지마다 초기화돼야 한다면 더 아래로 내리거나 템플릿을 써. 공통으로 보인다고 전부 루트 레이아웃에 올리면 앱 전체가 하나의 거대한 수명을 가져. 특정 구역에서만 필요한 provider와 데이터가 모든 페이지 비용이 될 수 있어. 가장 넓은 공통 조상이 아니라 필요한 범위의 가장 가까운 공통 조상에 배치해. 형제 페이지를 오가며 레이아웃의 입력 상태와 페이지의 입력 상태를 각각 바꿔 봐. 무엇이 남고 무엇이 초기화되는지 예상표와 비교하고, query string 변화가 레이아웃을 다시 그리지 않는다는 사실도 확인해. 수명 차이가 요구와 다르면 컴포넌트 위치부터 고쳐.

Code

필수 루트 레이아웃·tsx
// app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className="min-h-screen bg-white text-gray-900 antialiased">
        <SiteNav />
        <main className="mx-auto max-w-5xl p-6">{children}</main>
        <SiteFooter />
      </body>
    </html>
  );
}
params를 기다리는 중첩 레이아웃·tsx
// app/team/[teamId]/layout.tsx
export default async function TeamLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: Promise<{ teamId: string }>;
}) {
  const { teamId } = await params;
  return (
    <div className="grid grid-cols-[200px_1fr] gap-6">
      <TeamSidebar teamId={teamId} />
      {children}
    </div>
  );
}

External links

Exercise

/dashboard/...에 사이드바와 내비게이션이 있는 레이아웃을 만들어. 두 자식 페이지를 오갈 때 사이드바의 접힘 상태가 유지되는지 확인해.

Progress

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

댓글 0

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

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