문서
App Router 사용하기
layout.js

layout.js

레이아웃은 라우트 간에 공유되는 UI입니다.

app/dashboard/layout.tsx
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return <section>{children}</section>;
}
app/dashboard/layout.js
export default function DashboardLayout({ children }) {
  return <section>{children}</section>;
}

루트 레이아웃은 루트 app 디렉토리의 최상위 레이아웃입니다. 이는 <html><body> 태그 및 기타 전역적으로 공유되는 UI를 정의하는 데 사용됩니다.

app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}
app/layout.js
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Props

children (필수)

레이아웃 컴포넌트는 children prop을 받아 사용해야 합니다. 렌더링 중에 children은 레이아웃이 감싸고 있는 라우트 세그먼트로 채워집니다. 이는 주로 자식 레이아웃(존재하는 경우) 또는 페이지의 컴포넌트가 되지만, 해당되는 경우 로딩 또는 에러와 같은 다른 특수 파일일 수도 있습니다.

params (선택사항)

루트 세그먼트부터 해당 레이아웃까지의 동적 라우트 매개변수 객체입니다.

예시URLparams
app/dashboard/[team]/layout.js/dashboard/1{ team: '1' }
app/shop/[tag]/[item]/layout.js/shop/1/2{ tag: '1', item: '2' }
app/blog/[...slug]/layout.js/blog/1/2{ slug: ['1', '2'] }

예를 들어:

app/shop/[tag]/[item]/layout.tsx
export default function ShopLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: {
    tag: string;
    item: string;
  };
}) {
  // URL -> /shop/shoes/nike-air-max-97
  // `params` -> { tag: 'shoes', item: 'nike-air-max-97' }
  return <section>{children}</section>;
}
app/shop/[tag]/[item]/layout.js
export default function ShopLayout({ children, params }) {
  // URL -> /shop/shoes/nike-air-max-97
  // `params` -> { tag: 'shoes', item: 'nike-air-max-97' }
  return <section>{children}</section>;
}

알아두면 좋은 점

루트 레이아웃

  • app 디렉토리에는 반드시 루트 app/layout.js가 포함되어야 합니다.
  • 루트 레이아웃은 반드시 <html><body> 태그를 정의해야 합니다.
    • 루트 레이아웃에 <title><meta>와 같은 <head> 태그를 수동으로 추가해서는 안 됩니다. 대신 스트리밍 및 <head> 요소 중복 제거와 같은 고급 요구사항을 자동으로 처리하는 메타데이터 API를 사용해야 합니다.
  • 라우트 그룹을 사용하여 여러 루트 레이아웃을 만들 수 있습니다.
    • 여러 루트 레이아웃 간 탐색은 (클라이언트 측 탐색과 반대로) 전체 페이지 로드를 유발합니다. 예를 들어, app/(shop)/layout.js를 사용하는 /cart에서 app/(marketing)/layout.js를 사용하는 /blog로 탐색하면 전체 페이지 로드가 발생합니다. 이는 오직 여러 루트 레이아웃에만 적용됩니다.

레이아웃은 searchParams를 받지 않습니다

페이지와 달리, 레이아웃 컴포넌트는 searchParams prop을 받지 않습니다. 이는 공유 레이아웃이 탐색 중에 다시 렌더링되지 않기 때문입니다. 이는 탐색 간에 searchParams가 오래된 상태가 될 수 있습니다.

클라이언트 측 탐색을 사용할 때, Next.js는 자동으로 두 라우트 사이의 공통 레이아웃 아래에 있는 페이지의 일부만 렌더링합니다.

예를 들어, 다음과 같은 디렉토리 구조에서 dashboard/layout.tsx/dashboard/settings/dashboard/analytics 모두에 대한 공통 레이아웃입니다:

대시보드 폴더 내 layout.tsx 파일과 settings 및 analytics 폴더 각각의 페이지를 보여주는 파일 구조

/dashboard/settings에서 /dashboard/analytics로 탐색할 때, /dashboard/analyticspage.tsx는 서버에서 다시 렌더링되지만, dashboard/layout.tsx는 두 라우트 간에 공유되는 공통 UI이므로 다시 렌더링되지 않습니다.

이 성능 최적화를 통해 레이아웃을 공유하는 페이지 간의 탐색이 더 빨라집니다. 공유 레이아웃이 자체 데이터를 가져오는 전체 라우트 대신 페이지에 대한 데이터 가져오기와 렌더링만 실행하면 되기 때문입니다.

dashboard/layout.tsx가 다시 렌더링되지 않기 때문에, 레이아웃 서버 컴포넌트의 searchParams prop은 탐색 후에 오래된 상태가 될 수 있습니다.

대신, 페이지 searchParams prop을 사용하거나 클라이언트 컴포넌트에서 useSearchParams 훅을 사용하세요. 이는 최신 searchParams로 클라이언트에서 다시 렌더링됩니다.

레이아웃은 pathname에 접근할 수 없습니다

레이아웃은 pathname에 접근할 수 없습니다. 이는 레이아웃이 기본적으로 서버 컴포넌트이며, 클라이언트 측 탐색 중에 다시 렌더링되지 않기 때문입니다. 이는 탐색 간에 pathname이 오래된 상태가 될 수 있습니다. 오래된 상태를 방지하려면 Next.js가 라우트의 모든 세그먼트를 다시 가져와야 하는데, 이는 캐싱의 이점을 잃고 탐색 시 RSC 페이로드 크기를 증가시킵니다.

대신, pathname에 의존하는 로직을 클라이언트 컴포넌트로 추출하고 레이아웃으로 가져올 수 있습니다. 클라이언트 컴포넌트는 탐색 중에 다시 렌더링되기 때문에(다시 가져오지는 않음), usePathname과 같은 Next.js 훅을 사용하여 현재 pathname에 접근하고 오래된 상태를 방지할 수 있습니다.

app/dashboard/layout.tsx
import { ClientComponent } from '@/app/ui/ClientComponent'
 
export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <>
      <ClientComponent />
      {/* 기타 레이아웃 UI */}
      <main>{children}</main>
    <>
  )
}
app/dashboard/layout.js
import { ClientComponent } from '@/app/ui/ClientComponent'
 
export default function Layout({ children }) {
  return (
    <>
      <ClientComponent />
      {/* 기타 레이아웃 UI */}
      <main>{children}</main>
    <>
  )
}

일반적인 pathname 패턴은 params prop으로도 구현할 수 있습니다.

자세한 정보는 예제 섹션을 참조하세요.

버전 기록

버전변경 사항
v13.0.0layout 도입됨.