Active Link 를 만들기 위해 App router의 useSelectedLayoutSegment()
훅을 사용할 수 있다.
useSelectedLayoutSegment()
는 클라이언트 컴포넌트에서 사용되는 훅으로, 호출된 레이아웃보다 한 수준 아래에 있는 segment를 반환한다.useSelectedLayoutSegments
사용layout
이 속한 폴더를 기준으로 폴더가 같으면 null
, 다르면 바로 아래있는 segment
를 반환한다.useSelectedLayoutSegment()
는 클라이언트 컴포넌트 훅이고, 레이아웃은 서버 컴포넌트이므로, useSelectedLayoutSegment()
는 레이아웃으로 임포트된 클라이언트 컴포넌트를 통해서만 사용된다.page.tsx
에서 클라이언트 컴포넌트를 임포트해서 useSelectedLayoutSegment()
사용하면, null
을 반환한다.page.tsx
에서 현재 url을 가져오고 싶다면 usePathname()
을 사용하는 게 좋다.const segment = useSelectedLayoutSegment(parallelRoutesKey?: string)
'use client'
import { useSelectedLayoutSegment } from 'next/navigation'
export default function ExampleClientComponent() {
const segment = useSelectedLayoutSegment()
return <p>Active segment: {segment}</p>
}
useSelectedLayoutSegment
useSelectedLayoutSegments
useSelectedLayoutSegment()
를 이용해 segment를 가져와 segment와 일치하는 Active Link 를 만들 수 있다.// app/blog/blog-nav-link.tsx
'use client'
import Link from 'next/link'
import { useSelectedLayoutSegment } from 'next/navigation'
export default function BlogNavLink({
slug,
children,
}: {
slug: string
children: React.ReactNode
}) {
// `/blog/hello-world`로 이동하면 선택된 레이아웃 세그먼트에 'hello-world'가 반환
const segment = useSelectedLayoutSegment()
const isActive = slug === segment
return (
<Link
href={`/blog/${slug}`}
// 링크 활성 상태에 따라 스타일 변경
style={{ fontWeight: isActive ? 'bold' : 'normal' }}
>
{children}
</Link>
)
}
// app/blog/layout.tsx
// 클라이언트 컴포넌트를 부모 레이아웃(서버 컴포넌트)에 가져오기
import { BlogNavLink } from './blog-nav-link'
import getFeaturedPosts from './get-featured-posts'
export default async function Layout({
children,
}: {
children: React.ReactNode
}) {
const featuredPosts = await getFeaturedPosts()
return (
<div>
{featuredPosts.map((post) => (
<div key={post.id}>
<BlogNavLink slug={post.slug}>{post.title}</BlogNavLink>
</div>
))}
<div>{children}</div>
</div>
)
}
현재 URL 경로 정보를 알 수 있는 다른 훅들에 대해서도 알아보자 !
usePathname
은 대체 경로가 렌더링되거나 Next.js에 의해 페이지 디렉토리 페이지가 자동으로 정적으로 최적화되었을 때 및 라우터가 준비되지 않은 경우에 null
을 반환한다.const pathname = usePathname()
// app/example-client-component.tsx
'use client'
import { usePathname } from 'next/navigation'
export default function ExampleClientComponent() {
const pathname = usePathname()
return <p>Current pathname: {pathname}</p>
}
useParams
는 빈 객체를 반환한다.const params = useParams()
// app/example-client-component.tsx
'use client'
import { useParams } from 'next/navigation'
export default function ExampleClientComponent() {
const params = useParams<{ tag: string; item: string }>()
// 라우트 -> /shop/[tag]/[item]
// URL -> /shop/shoes/nike-air-max-97
// `params` -> { tag: 'shoes', item: 'nike-air-max-97' }
console.log(params)
return <></>
}
URLSearchParams.get()
: 파라미터의 첫번째 value를 반환URLSearchParams.has()
: 파라미터의 존재 여부 반환URLSearchParams.getAll()
: 모든 파라미터의 value를 문자열로 반환URLSearchParams.keys()
: 모든 파라미터의 key를 문자열로 반환URLSearchParams.entries()
: 모든 파라미터의 key와 value를 문자열로 반환URLSearchParams.toString()
: 현재 쿼리 스트링을 문자열로 반환const searchParams = useSearchParams()
'use client'
import { useSearchParams } from 'next/navigation'
export default function SearchBar() {
const searchParams = useSearchParams()
const search = searchParams.get('search')
// URL -> `/dashboard?search=my-project`
// `search` -> 'my-project'
return <>Search: {search}</>
}