Next.js의 라우터는 클라이언트 사이드 네비게이션과 함께, 서버 중심적 라우팅을 사용합니다. 이는 즉각적인 로딩 상태과 동시 렌더링을 지원합니다. 즉, 네비게이션은 클라이언트 측 상태를 유지하며, 무거운 리렌더를 피하고, 중단 가능하며, 레이스 컨디션(race conditions)를 일으키지 않는다는 것을 의미합니다.
루트 간 네비게이션을 위한 두 가지 방법이 있습니다:
<Link>
컴포넌트useRouter
훅해당 페이지에서는 <Link>
와 useRouter()
을 어떻게 사용하는지 알아보고, 네비게이션이 어떻게 동작하는지 더 깊이 이해해 봅시다.
<Link>
Component (<Link>
컴포넌트)<Link>
는 프리페치와 루트 간의 클라이언트 사이드 네비게이션을 제공하기 위해 만들어진, HTML의 <a>
태그를 확장한 리액트 컴포넌트입니다.이는 Next.js 안에서 루트 간 네비게이팅을 지원하는 가장 주요한 방법입니다.
// app/page.tsx
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>;
}
<Link>
에 넘길 수 있는 다른 선택적인 props 들이 있습니다. 더 많은 정보는 API 레퍼런스를 참조하세요.
동적 세그먼트에 연결할 때는, 링크 리스트를 생성하기 위해 템플릿 리터럴과 인터폴레이션을 사용할 수 있습니다.예를 들어, 블로그 포스트 리스트를 생성하기 위해서는 아래와 같이 할 수 있습니다.
// app/blog/PostList.jsx
export default function PostList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>
{post.title}
</Link>
</li>
))}
</ul>
)
}
useRouter()
Hook (useRouter()
훅)useRouter
훅은 클라이언트 컴포넌트 안에서 프로그래머틱하게 루트를 변경할 수 있도록 도와줍니다.
useRouter
훅을 사용하기 위해서는, next/navigation
에서 임포트하고, 클라이언트 컴포넌트 안에서 해당 훅을 호출하면 됩니다.
'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 레퍼런스를 확인하세요.
추천: 특별히
useRouter
을 이용해야 할 이유가 없다면, 루트 간 네비게이팅을 위해Link
컴포넌트를 사용하세요.
<Link>
컴포넌트를 이용하거나 router.push()
메서드를 호출해서 촉발됩니다.알아두면 좋은 것: 클라이언트 사이드 캐시는 서버 사이드 Next.js HTTP 캐시와는 다릅니다.
새로운 라우터는 인-메모리 클라이언트 사이드 캐시를 가지고 있으며, 이는 서버 컴포넌트 (페이로드)의 렌더링 결과물을 저장합니다. 이 캐시는 루트 세그먼트에 의해 분할되고, 어떤 레벨에서든 무효화를 지원하며, 동시에 발생하는 렌더들 사이에 일관성을 보장합니다.
유저가 앱을 탐방할 때, 라우터는 이전에 페치한 세그먼트의 페이로드와 캐시에서 프리페치한 세그먼트를 저장할 것입니다.
이는 특정한 상황에서, 라우터가 서버에 새로운 요청을 보내는 대신 캐시를 재사용할 수 있음을 뜻합니다. 불필요한 컴포넌트의 리렌더나 데이터를 다시 가져오는 것을 피하면서, 퍼포먼스를 향상시킬 수 있습니다.
router.refresh()
를 이용해서 루트를 새로고침 할 수 있습니다. 이는 서버에 새로운 요청을 만들고, 데이터 리퀘스트를 새로 가져오며 서버 컴포넌트를 리렌더링합니다. 더 많은 정보는 API 레퍼런스를 참조하세요. 추후에는 뮤테이션의 경우 자동으로 캐시를 무효화하게 될 겁니다.
프리페칭은 유저가 방문하기 전에 백그라운드에서 루트를 미리 로드하는 방법입니다. 프리페치 된 루트들의 렌더링 결과물은 라우터의 클라이언트 사이드 캐시에 저장됩니다. 이는 프리페칭된 루트에 거의 즉각적으로 네비게이팅 할 수 있도록 만들어 줍니다.
기본적으로 <Link>
컴포넌트를 이용했을 경우, 뷰포트 안에서 보여지게 될 때 루트들은 프리페치 됩니다. 이는 페이지가 가장 처음 로드될 때나 스크롤을 통해서 일어날 수 있습니다. 루트들은 또한 useRouter() 훅의 prefetch
메서드를 통해 프로그래머틱하게 프리페치 될 수 있습니다.
정적/동적 루트들:
loading.js
파일의 페이로드가 프리페치 될 겁니다. 이는 모든 루트를 동적으로 프리페칭하는 것의 비용을 줄여주며, 동적 루트들에서 즉각적인 로딩 상태를 만들 수 있게 도와줍니다.알아두면 좋은 것:
<Link>
컴포넌트에서 prefetch={false}
를 넘겨서 비활성화 할 수 있습니다.네비게이션에서, 캐시는 무효화되고 서버는 데이터를 다시 가져오며, 변경된 세그먼트를 리렌더링 합니다.
네비게이션에서, 변경된 세그먼트의 캐시가 존재할 경우 재사용되며, 데이터를 가져오기 위해 서버에 새로운 요청을 만들지 않습니다.
네비게이션에서, 이동하고 있는 라우트가 프리페치 되고 있는 와중이고, 동적 세그먼트나 현재 라우트와 동일한 동적 파라미터를 포함하고 있지 않은 상태라면 Next.js는 소프트 네비게이션을 사용할 것입니다.
예를 들어, [team]
이라는 동적 세그먼트를 포함하고 있는 다음과 같은 루트를 상상해 봅시다: /dashboard/[team]/*
. 만약 [team]
파라미터가 변경되면, /dashboard/[team]/*
하위의 캐싱된 세그먼트들만 무효화 될 겁니다.
/dashboard/team-red/*
에서 /dashboard/team-red/*
로의 이동은 소프트 네비게이션입니다./dashboard/team-red/*
에서 /dashboard/team-blue/*
로의 이동은 하드 네비게이션입니다.이전/다음 네비게이션 (popstate 이벤트)는 소프트 네비게이션 행동 양식을 갖고 있습니다. 이는, 클라이언트 사이드 캐시가 재사용되며, 네비게이션이 거의 즉각적이라는 뜻입니다.
기본적으로, Next.js는 네비게이션을 통해 변화한 세그먼트 뷰에 포커스와 스크롤을 적용합니다. 이러한 접근성과 사용성 기능은 향상된 라우팅 패턴이 적용되었을 때 더욱 명백하게 중요해집니다.