layout.js
레이아웃은 라우트 간에 공유되는 UI입니다.
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return <section>{children}</section>;
}
export default function DashboardLayout({ children }) {
return <section>{children}</section>;
}
루트 레이아웃은 루트 app
디렉토리의 최상위 레이아웃입니다. 이는 <html>
과 <body>
태그 및 기타 전역적으로 공유되는 UI를 정의하는 데 사용됩니다.
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
Props
children
(필수)
레이아웃 컴포넌트는 children
prop을 받아 사용해야 합니다. 렌더링 중에 children
은 레이아웃이 감싸고 있는 라우트 세그먼트로 채워집니다. 이는 주로 자식 레이아웃(존재하는 경우) 또는 페이지의 컴포넌트가 되지만, 해당되는 경우 로딩 또는 에러와 같은 다른 특수 파일일 수도 있습니다.
params
(선택사항)
루트 세그먼트부터 해당 레이아웃까지의 동적 라우트 매개변수 객체입니다.
예시 | URL | params |
---|---|---|
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'] } |
예를 들어:
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>;
}
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
모두에 대한 공통 레이아웃입니다:

/dashboard/settings
에서 /dashboard/analytics
로 탐색할 때, /dashboard/analytics
의 page.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에 접근하고 오래된 상태를 방지할 수 있습니다.
import { ClientComponent } from '@/app/ui/ClientComponent'
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<ClientComponent />
{/* 기타 레이아웃 UI */}
<main>{children}</main>
<>
)
}
import { ClientComponent } from '@/app/ui/ClientComponent'
export default function Layout({ children }) {
return (
<>
<ClientComponent />
{/* 기타 레이아웃 UI */}
<main>{children}</main>
<>
)
}
일반적인 pathname
패턴은 params
prop으로도 구현할 수 있습니다.
자세한 정보는 예제 섹션을 참조하세요.
버전 기록
버전 | 변경 사항 |
---|---|
v13.0.0 | layout 도입됨. |