useSelectedLayoutSegments#
- 상위 메뉴: Functions
- 전체 목차: Next.js 학습 문서
학습 목표#
- Client Component에서 해당 레이아웃 하위의 모든 활성 라우트 세그먼트 배열을 읽는
useSelectedLayoutSegments훅의 역할을 이해한다. - 브레드크럼(Breadcrumbs)과 같은 다계층 내비게이션 UI를 구현할 때 세그먼트 목록을 활용하는 방법을 습득한다.
- Route Groups 괄호 표기(
(group)) 및 Catch-all 라우트([...slug])가 배열에 포함되는 형태를 이해하고 필터링 처리한다. - Parallel Routes 슬롯(
parallelRoutesKey) 인자 사용법과Suspense경계 적용 원리를 설명한다.
핵심 개념 및 설명#
useSelectedLayoutSegments는 이 훅이 호출된 레이아웃 아래의 모든 활성 라우트 세그먼트 목록을 문자열 배열(string[])로 읽을 수 있는 Client Component 전용 훅이다.
루트 레이아웃이나 상위 레이아웃에서 하위 경로 전체의 구조를 파악하여 브레드크럼(경로 이동 경로 표시)을 생성할 때 매우 유용하다.
app/example-client-component.tsxtsx
'use client'
import { useSelectedLayoutSegments } from 'next/navigation'
export default function ExampleClientComponent() {
const segments = useSelectedLayoutSegments()
return (
<ul>
{segments.map((segment, index) => (
<li key={index}>{segment}</li>
))}
</ul>
)
}app/example-client-component.jsjsx
'use client'
import { useSelectedLayoutSegments } from 'next/navigation'
export default function ExampleClientComponent() {
const segments = useSelectedLayoutSegments()
return (
<ul>
{segments.map((segment, index) => (
<li key={index}>{segment}</li>
))}
</ul>
)
}알아두면 좋은 점:
- useSelectedLayoutSegments는 Client Component 훅이고 레이아웃은 기본적으로 Server Component이므로, 일반적으로 레이아웃에 임포트되는 별도의 Client Component 내부에서 호출한다.- 반환되는 세그먼트 배열에는 Route Groups 세그먼트(예:(marketing))가 포함될 수 있다. UI에 노출하고 싶지 않다면segments.filter(segment => !segment.startsWith('('))형태로 제거한다.
- Catch-all 라우트([...slug])의 경우 매칭된 경로들이 배열 내에 개별 원소가 아닌 결합된 단일 문자열('a/b/c')로 반환된다. 예를 들어app/layout.js에서/blog/a/b/c방문 시['blog', 'a/b/c']가 반환된다.
매개변수 (Parameters)#
app/example-client-component.tsxtsx
const segments = useSelectedLayoutSegments(parallelRoutesKey?: string)useSelectedLayoutSegments는 선택적으로 parallelRoutesKey 문자열을 인자로 전달받아 특정 Parallel Routes 슬롯 내부의 하위 세그먼트 목록을 읽을 수 있다.
반환값 (Returns)#
호출된 레이아웃 하위의 활성 세그먼트들이 순서대로 담긴 문자열 배열(string[])을 반환한다. 하위 세그먼트가 없으면 빈 배열([])을 반환한다.
| 레이아웃 위치 | 방문 URL | 반환 세그먼트 배열 |
|---|---|---|
app/layout.js | / | [] |
app/layout.js | /dashboard | ['dashboard'] |
app/layout.js | /dashboard/settings | ['dashboard', 'settings'] |
app/dashboard/layout.js | /dashboard | [] |
app/dashboard/layout.js | /dashboard/settings | ['settings'] |
Catch-all 라우트([...slug])의 경우:
| 레이아웃 위치 | 방문 URL | 반환 세그먼트 배열 |
|---|---|---|
app/layout.js | /blog/a/b/c | ['blog', 'a/b/c'] |
app/blog/layout.js | /blog/a/b/c | ['a/b/c'] |
동작 방식 (Behavior)#
Cache Components 및 Suspense 경계#
`cacheComponents`가 활성화되어 있을 때:
- 정적 라우트나
generateStaticParams로 확정된 라우트는 서버에서 즉시 계산되어Suspense경계가 필요 없다. - 빌드 시점에 결정되지 않는 fallback params가 포함된 경우
useSelectedLayoutSegments가 suspend되므로, 상위에 fallback이 지정된<Suspense>경계를 배치해야 레이아웃의 나머지 영역이 온전히 prerender된다.
예제#
브레드크럼(Breadcrumbs) 내비게이션 구현#
상위 레이아웃에서 현재 경로의 모든 세그먼트를 순회하며 링크가 포함된 브레드크럼 목록을 동적으로 구성할 수 있다.
app/components/breadcrumbs.tsxtsx
'use client'
import Link from 'next/link'
import { useSelectedLayoutSegments } from 'next/navigation'
export function Breadcrumbs() {
const segments = useSelectedLayoutSegments()
// 라우트 그룹((marketing), (shop) 등) 제외 필터링
const filteredSegments = segments.filter((s) => !s.startsWith('('))
return (
<nav aria-label="Breadcrumb" className="p-4 bg-gray-50 border-b">
<ol className="flex items-center space-x-2 text-sm text-gray-600">
<li>
<Link href="/" className="hover:underline">홈</Link>
</li>
{filteredSegments.map((segment, index) => {
const href = `/${filteredSegments.slice(0, index + 1).join('/')}`
const isLast = index === filteredSegments.length - 1
return (
<li key={href} className="flex items-center space-x-2">
<span>/</span>
{isLast ? (
<span className="font-semibold text-gray-900">{segment}</span>
) : (
<Link href={href} className="hover:underline">{segment}</Link>
)}
</li>
)
})}
</ol>
</nav>
)
}app/components/breadcrumbs.jsjsx
'use client'
import Link from 'next/link'
import { useSelectedLayoutSegments } from 'next/navigation'
export function Breadcrumbs() {
const segments = useSelectedLayoutSegments()
const filteredSegments = segments.filter((s) => !s.startsWith('('))
return (
<nav aria-label="Breadcrumb" className="p-4 bg-gray-50 border-b">
<ol className="flex items-center space-x-2 text-sm text-gray-600">
<li>
<Link href="/" className="hover:underline">홈</Link>
</li>
{filteredSegments.map((segment, index) => {
const href = `/${filteredSegments.slice(0, index + 1).join('/')}`
const isLast = index === filteredSegments.length - 1
return (
<li key={href} className="flex items-center space-x-2">
<span>/</span>
{isLast ? (
<span className="font-semibold text-gray-900">{segment}</span>
) : (
<Link href={href} className="hover:underline">{segment}</Link>
)}
</li>
)
})}
</ol>
</nav>
)
}이 컴포넌트를 루트 레이아웃에 배치한다:
app/layout.tsxtsx
import { Breadcrumbs } from './components/breadcrumbs'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="ko">
<body>
<Breadcrumbs />
<main>{children}</main>
</body>
</html>
)
}Version History#
| 버전 | 변경 사항 |
|---|---|
v13.0.0 | useSelectedLayoutSegments 도입 |
예제 및 데모 설계#
- 중첩 라우트(
/dashboard/analytics/users/retention)에서 루트 레이아웃과 서브 레이아웃 각각에서 반환되는 세그먼트 배열의 길이 및 구성을 비교하는 데모를 설계한다. (marketing)과 같은 Route Groups가 포함된 경로에서 필터링 전후의 배열 출력을 확인한다.app/layout.tsx에서 브레드크럼 UI를 렌더링하고 각 경로 클릭 시 올바른 URL로 내비게이션되는지 검증한다.
연습 문제#
- 루트 레이아웃
app/layout.js에서useSelectedLayoutSegments()를 호출했을 때, 브라우저가/dashboard/settings/profile에 접근 중이라면 반환값은?
- A.
'profile' - B.
['dashboard', 'settings', 'profile'] - C.
['settings', 'profile'] - D.
['dashboard/settings/profile']
정답 보기
정답: B
해설: 루트 레이아웃 기준 하위의 모든 활성 세그먼트가 배열 형태인 ['dashboard', 'settings', 'profile']로 반환된다.
useSelectedLayoutSegments반환값에서 Route Groups(예:(admin))를 브레드크럼 UI에서 제외하고자 할 때 권장되는 방식은?
- A.
next.config.js에서 라우트 그룹 비활성화 - B.
segments.filter(segment => !segment.startsWith('('))와 같이 배열 필터링 적용 - C.
useSelectedLayoutSegments({ excludeGroups: true })옵션 전달 - D. Server Component로만 라우트 그룹 감싸기
정답 보기
정답: B
해설: 반환된 세그먼트 배열에 포함된 Route Groups 괄호 명칭은 자바스크립트의 filter 메서드를 사용해 간편하게 걸러낼 수 있다.
챕터 요약#
useSelectedLayoutSegments는 호출된 레이아웃 하위의 모든 활성 라우트 세그먼트를 문자열 배열로 반환하는 Client Component 훅이다.- 하위 세그먼트가 존재하지 않으면 빈 배열(
[])을 반환한다. - 다계층 브레드크럼(Breadcrumbs) 컴포넌트 구현에 핵심적으로 활용된다.
- Route Groups(
(group)) 이름도 배열에 포함되므로 UI 필요에 따라filter로 제외 처리할 수 있다. - Catch-all 세그먼트는 배열 내 하나의 원소에 슬래시로 묶인 결합 문자열로 반환된다.