Next.js 라우터는 server-centric routing과 client-side navigation을 사용한다. 이는 즉각적인 로딩 상태와 동시 렌더링을 지원한다. 내비게이션이 클라이언트 측 상태를 유지하고 비용이 많이 드는 리렌더링을 피하며, 중단 가능하며 race condition을 발생시키지 않는다는 것을 의미한다.
<Link>
ComponentuseRouter
HookLink 컴포넌트
<Link>
는 HTML <a>
요소를 확장하여 라우트 간 사전 로딩과 클라이언트 측 내비게이션을 제공하는 React 컴포넌트이다. Next.js에서 라우트 간 이동하는 주요한 방법이다.
<Link>
를 사용하려면 next/link
에서 import하고 컴포넌트에 href
속성을 전달하면 된다.
import Link from 'next/link';
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>;
}
동적 세그먼트에 연결할 때, 템플릿 리터럴(``)
과 보간(${})
을 사용하여 링크 목록을 생성할 수 있다.
예를 들어, 블로그 글 목록을 생성하려면 다음과 같이 할 수 있다.
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
와 일치하는지 확인하여 활성 링크에 클래스를 추가할 수 있다.
'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로 스크롤된다.
경로 세그먼트의 맨 위로 스크롤되는 것을 방지하려면 scroll={false}
를 설정하고 href
에 해시된 id
를 추가한다.
<Link href="/#hashid" scroll={false}>
Scroll to specific id.
</Link>
useRouter( )
useRouter
훅을 사용하면 클라이언트 컴포넌트 내에서 프로그래밍 방식으로 경로를 변경할 수 있다.
useRouter
를 사용하려면 next/navigation
에서 import
하고 클라이언트 컴포넌트 내에서 해당 훅을 호출하면 된다.
'use client';
import { useRouter } from 'next/navigation';
export default function Page() {
const router = useRouter();
return (
// '/dashboard'로 이동
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
);
}
이외에도 useRouter()
는 push()
, refresh()
등의 메소드를 제공한다.
네비게이션 작동 방식
<Link>
를 사용하거나 router.push()
를 호출하여 경로 전환이 시작된다.이 클라이언트 측 캐시는 서버 측 Next.js HTTP 캐시와 다르다.
새로운 라우터에는 서버 컴포넌트(페이로드)의 렌더링 결과를 저장하는 인메모리 클라이언트 측 캐시가 있다. 이 캐시는 경로 세그먼트별로 분할되어 임의의 레벨에서 무효화가 가능하며, 동시에 렌더링되는 컴포넌트 간 일관성을 보장한다.
사용자가 앱을 탐색하는 동안, 라우터는 이전에 가져온 세그먼트의 페이로드와 사전로드된 세그먼트의 페이로드를 캐시에 저장한다.
이는 특정 경우에 라우터가 새로운 서버 요청을 하지 않고 캐시를 재사용할 수 있다는 것을 의미한다. 이는 데이터를 다시 가져오거나 컴포넌트를 불필요하게 다시 렌더링하는 것을 피함으로써 성능을 향상시킨다.
서버 액션은 경로(revalidatePath
) 또는 캐시 태그(revalidateTag
)별로 필요에 따라 데이터를 다시 유효성 검사하는 데 사용할 수 있다.
사전로드는 방문하기 전에 백그라운드에서 경로를 미리 로드하는 방법이다. 사전로드된 경로의 렌더링 결과는 라우터의 클라이언트 측 캐시에 추가된다. 이를 통해 사전로드된 경로로의 이동이 거의 빠르게 이루어진다.
기본적으로 <Link>
컴포넌트를 사용할 때 뷰포트에 표시되는 순간 경로가 사전로드된다. 이는 페이지가 처음 로드되거나 스크롤하는 경우에 발생할 수 있다. 또한 useRouter()
훅의 prefetch 메서드를 사용하여 프로그래밍 방식으로 경로를 사전로드할 수도 있다.
💡 정적 및 동적 경로
loading.js
파일까지의 페이로드가 사전로드된다. 이는 경로 전체를 동적으로 사전로드하는 비용을 줄이고 동적 경로에 대한 즉시 로딩 상태를 제공한다.💡 알아두면 좋은 점
<Link>
에 prefetch={false}
를 전달하여 사전로드를 비활성화할 수 있다.네비게이션 시 캐시가 무효화되고 서버가 데이터를 다시 가져와 변경된 세그먼트를 다시 렌더링한다.
네비게이션 시 변경된 세그먼트의 캐시가 재사용되고 (캐시가 존재하는 경우) 데이터를 위해 새로운 서버 요청이 발생하지 않는다.
💡 소프트 네비게이션의 조건
네비게이션 시 Next.js는 소프트 네비게이션을 사용한다. 이는 네비게이션하려는 경로가 사전로드된 경우이며, 동적 세그먼트를 포함하지 않거나 현재 경로와 동일한 동적 매개변수를 가지는 경우이다.
👇 예를 들어, 다음과 같은 동적 [team]
세그먼트를 포함하는 경로를 고려해보자.
/dashboard/[team]/**
아래에 캐시된 세그먼트는 [team]
매개변수가 변경될 때만 무효화된다./dashboard/team-red/*
에서 /dashboard/team-red/*
로 이동하는 경우, 소프트 네비게이션으로 처리된다./dashboard/team-red/*
에서 /dashboard/team-blue/*
로 이동하는 경우, 하드 네비게이션으로 처리된다.뒤로 및 앞으로 이동 네비게이션(popstate 이벤트)은 소프트 네비게이션 동작을 가지고 있다. 이는 클라이언트 측 캐시가 재사용되고 네비게이션이 거의 즉시 이루어진다는 것을 의미한다.
기본적으로 Next.js는 네비게이션 시 변경된 세그먼트에 포커스를 설정하고 스크롤을 뷰에 맞춘다.
[출처]
https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating