Next.js 라우터는 서버 중심 라우팅과 클라이언트 사이드 네비게이션을 사용하고 있습니다.
이 기능을 통해 바로 스테이트를 로딩하고 동시성 렌더링을 지원할 수 있습니다.
이는 네비게이션이 클라이언트 사이드 스테이트를 유지할 수 있고 비싼 연산에 속하는 리렌더링을 피할 수 있고 중간에 렌더링 프로세스를 가로챌 수 있기 때문에 레이스 컨디션을 발생 시키지 않습니다.
라우트 사이에 네비게이션을 할 수 있는 방법에는 2가지 정도 있습니다.
이번 문서에선 어떻게 <Link>
컴포넌트와 useRouter()
훅을 사용하는지 알아볼 것이며 어떻게 네비게이션이 동작하는지 자세히 알아봅니다.
<Link>
Component<Link>
컴포넌트는 HTML의 <a>
태그를 확장시킨 리액트 컴포넌트로 라우트 사이에 프리패치와 클라이언트 사이드 네비게이션을 처리할 수 있도록 도와줍니다.
해당 컴포넌트를 사용하는 것이 Next.js에서 라우트 사이에 네비게이션을 할 수 있는 가장 기본적인 방법입니다.
<Link>
컴포넌트를 사용하기 위해선 next/link
패키지를 import 하고 컴포넌트에 href
프롭을 전달하면 됩니다.
import Link from 'next/link'
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>
}
<Link>
컴포넌트에 전달할 수 있는 부가적인 옵션 프롭도 존재합니다.
더 자세한 정보는 API Reference 페이지에서 확인하세요.
다이나믹 세그먼트를 링크할 때 템플릿 리터럴과 템플릿 인터폴레이션을 사용하여 링크 리스트를 만들어 낼 수 있습니다.
예를 들어 블로그 포스트의 리스트를 만들기 위해선 아래와 같이 작성하면 됩니다.
import Link from 'next/link'
export default function PostList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
)
}
usePathname()
훅을 사용하여 현재 링크가 액티브 상태인지 확인할 수 있습니다.
예를 들어 액티브 상태의 링크에 클래스를 추가하고 싶다면 링크의 href
값이 현재 pathname
과 일치하는지 체크해 보면 됩니다.
'use client'
import { usePathname } from 'next/navigation'
import Link from 'next/link'
export function Navigation({ navLinks }) {
const pathname = usePathname()
return (
<>
{navLinks.map((link) => {
const isActive = pathname.startsWith(link.href)
return (
<Link
className={isActive ? 'text-blue' : 'text-black'}
href={link.href}
key={link.name}
>
{link.name}
</Link>
)
})}
</>
)
}
<Link>
컴포넌트의 기본 동작 방식은 변경 된 라우트 세그먼트의 최상단으로 스크롤 되는 것입니다.
href
값에 id
값이 명시되어 있다면 평범한 <a>
태그 처럼 해당하는 id
값이 담긴 엘리먼트로 스크롤 됩니다.
useRouter()
HookuseRouter
훅은 클라이언트 컴포넌트 안에서 프로그래밍적으로 라우트를 변경할 수 있도록 도와줍니다.
useRouter
훅을 사용하기 위해선 next/navigation
패키지를 import 하여 클라이언트 컴포넌트 내부에서 호출하면 됩니다.
'use client'
import { useRouter } from 'next/navigation'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}
useRouter
훅은 push()
, refresh()
와 같은 함수들을 제공합니다.
더 많은 정보를 얻고 싶다면 API reference 페이지에서 확인하세요.
추천 사항:
특별한 요구사항으로useRouter
를 사용해야 하는게 아니라면<Link>
컴포넌트를 사용하여 네비게이션을 처리하세요.
<Link>
컴포넌트 혹은 router.push()
를 호출하는 경우 라우터 변경이 이루어집니다.참고 사항:
클라이언트 사이드 캐시는 서버 사이드 Next.js HTTP 캐시와는 다릅니다.
새롭게 도입 된 라우터는 서버 컴포넌트의 페이로드의 렌더링 결과물을 저장하고 있는 인메모리 클라이언트 사이드 캐시를 가지고 있습니다.
캐시는 라우트 세그먼트에 따라 구분되며 어느 레벨에서도 재검증을 요청할 수 있고 동시성 렌더링 과정 중에 일관성을 유지할 수 있습니다.
유저가 어플리케이션을 네비게이션 할 때 라우터는 이전에 패치받은 세그먼트의 페이로드를 저장하고 캐시에서 세그먼트를 프리패치합니다.
이는 특정 케이스에선 라우터가 서버에 새로운 요청을 보내지 않고 캐시를 재사용할 수 있다는 것입니다.
이 방식은 불필요하게 데이터를 다시 패치하고 리렌더링 하지 않기 때문에 퍼포먼스를 향상시킬 수 있습니다.
서버 액션은 주소(revalidatePath
) 혹은 캐시 태그(revalidateTag
)에 따라 온디맨드로 데이터를 재검증할 수 있습니다.
프리패치는 방문하기 전에 미리 백그라운드에서 라우트를 로딩하는 방법을 말합니다.
프리패치한 라우트의 렌더링 결과물은 라우터의 클라이언트 사이드 캐시에 추가 됩니다.
이 방식을 사용하여 프리패치 한 라우트로 이동하는게 순식간에 일어나는 것 처럼 보이게 됩니다.
기본적으로 라우트는 <Link>
컴포넌트를 사용하고 있으면 뷰포트에서 보여졌을 때 프리패치 됩니다.
이는 초기 페이지 로딩이나 스크롤을 통해 발생할 수 있습니다.
라우트는 useRouter()
훅의 prefetch
메소드를 통해 프로그래밍적으로 프리패치 될 수 있습니다.
loading.js
파일을 마주치기 전 공유 레이아웃까지가 프리패치 됩니다. 이는 다이나믹하게 라우트 전체를 프리패치할때 발생하는 비용을 줄여주고 다이나믹 라우트에 바로 로딩 스테이트를 사용할 수 있게 해줍니다.참고 사항:
- 프리패치는 프로덕션 모드에서만 사용할 수 있습니다.
- 프리패치는
<Link>
컴포넌트에prefetch={false}
를 전달하여 비활성화 시킬 수 있습니다.
네비게이션에서 변경 된 세그먼트의 캐시는 존재한다면 재사용 되고 서버에 요청을 보내지 않습니다.
네비게이션에서 Next.js는 방문할 라우트가 프리패치 되어 있고 다이나믹 세그먼트를 포함하지 않거나 현재 라우트와 동일한 다이나믹 파라미터를 가지고 있다면 소프트 네비게이션을 사용합니다.
예를 들어 다이나믹 세그먼트인 [team]
을 포함하는 /dashboard/[team]/*
라우트를 생각해 봅시다
/dashboard/[team]/*
아래의 캐시 처리 된 세그먼트는 [team]
파라미터가 변경 될 때만 재검증 처리 될 것입니다.
/dashboard/team-red/*
에서 /dashboard/team-red/*
로의 네비게이션은 소프트 네비게이션으로 처리 됩니다./dashboard/team-red/*
에서 /dashboard/team-blue/*
로의 네비게이션은 하드 네비게이션으로 처리 됩니다.캐시는 무효화 처리 되고 서버는 데이터를 패치하며 변경 된 세그먼트에 맞게 리렌더링 되는 네비게이션 방법입니다.
Back/Forward Navigation (popstate event) 는 소프트 네비게이션 방식으러 처리 됩니다.
이는 클라이언트 사이드 캐시가 재사용 되고 네비게이션은 순식간에 처리됩니다.
기본적으로 Next.js는 네비게이션에서 변경 되는 세그먼트로 포커스가 맞춰지고 뷰포트에 들어올 수 있도록 스크롤 됩니다.