NextJS Router는 클라이언트 측 네비게이션과 서버 중심 라우팅의 장점을 결합하여, 사용자가 부드럽고 효율적인 네비게이션 경험을 할 수 있도록 설계되었다. 장점으로 즉각적인 로딩 상태와 동시 렌더링, 클라이언트 측 상태 유지, 비용이 많이 드는 리랜더링 방지, 중단 가능, Race Condition 방지 등이 있다.
Link 컴포넌트
<Link> 컴포넌트는 HTML의 <a> 태그를 확장하여 라우트 간 Prefetching과 클라이언트 측 네비게이션을 제공한다. NextJS에서 Navigating을 하는 주요 방법이다. 서버, 클라이언트 컴포넌트 모두에 사용할 수 있으며, 이동할 경로를 href props에 전달하면 사용할 수 있다.
import Link from 'next/link'
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>
}
Id로 스크롤하기
<Link>의 기본 동작은 변경된 Route Segment의 상단으로 스크롤하는 것이다. 이때 herf에 정의된 ID가 있다면 일반 <a> 태그와 유사하게 특정 ID로 스크롤 된다.
import Link from "next/link";
const LinkingAndNavigating = () => {
return (
<div className="flex flex-col">
<Link href="/linking-and-navigating/dashboard#position">
</Link>
</div>
);
};
export default LinkingAndNavigating;
스크롤 복원 비활성화
NextJS App Router의 기본 동작은 새로운 경로로 이동할 때 화면을 맨 위로 스크롤하는 것이다. 이 동작을 비활성화하려면, <Link> 컴포넌트에 scroll={false}를 전달하거나, router.push() 또는 router.replace()에 scroll: false 를 전달하면 된다.
// next/link
<Link href="/dashboard" scroll={false}>
Dashboard
</Link>
// useRouter
import { useRouter } from 'next/navigation'
const router = useRouter()
router.push('/dashboard', { scroll: false })
useRouter
useRouter를 사용하면 클라이언트 컴포넌트 내에서 프로그래밍 방식으로 라우트를 변경할 수 있다. 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>
)
}
router.push(herf) : 제공된 라우트로 클라이언트 측 Navigating을 수행한다.
router.replace(herf) : 브라우저 히스토리 스택에 새 항목을 추가하지 않고 클라이언트 측 Navigating을 수행한다.
router.refresh() : 현재 경로를 새로 고친다. 서버에 새 요청을 하고, 서버 컴포넌트를 다시 랜더링한다.
router.back() : Soft Navigation을 사용하여 브라우저의 히스트리 스택에서 이전 경로로 이동한다.
router.forward() : Soft Navigation을 사용하여 브라우저의 히스트리 스택에서 다음 경로로 이동한다.
네비게이션 동작 순서
<Link>를 사용하거나 router.push()를 호출하여 경로 전환이 시작된다. 라우터는 브라우저 주소 표시줄에서 URL을 업데이트한다.
라우터는 클라이언트 측 Router Cache에서 존재하는 세그먼트를 재사용하여 불필요한 작업을 피한다. 이를 부분 랜더링이라고 한다. Soft Navigation 조건이 충족되면 라우터는 서버가 아닌 캐시에서 새 새그먼트를 가져온다. 그렇지 않은 경우 라우터는 Hard Navigation을 수행하고 Full Route Cache, Data Cache, Data Source 순으로 컴포넌트 페이로드(bundle, props, HTML, JSON 등 랜더링 결과에 관련된 모든 데이터)를 가져온다.
페이로드를 가져오는 동안 로딩 UI가 표시된다. 라우터는 캐시된 페이로드 또는 새로운 페이로드를 사용하여 클라이언트에서 새 새그먼트를 랜더링한다.
Prefetching
Prefetching은 라우트에 방문하기 전에 백그라운드에서 미리 로드하는 방식이다. Prefetching 된 경로의 랜더링 결과는 클라이언트 측 Router Cache에 추가된다. 이렇게 하면 Prefetching된 경로로 거의 즉시 이동할 수 있다.
기본적으로 라우트는 <Link> 컴포넌트를 사용할 때 뷰포트에 표시되는 대로 Prefetching된다. 페이지 첫 로드 시 또는 스크롤 시Prefetching이 수행될 수 있다 . useRouter() 훅의 prefetch 메서드를 사용하여 프로그래밍 방식으로 라우트를 Prefetching 할 수 있다.
라우트가 정적 라우트인 경우, Route Segment에 필요한 모든 서버 컴포넌트의 페이로드가 Prefetching 된다. 라우트가 동적 라우트인 경우, 모든 데이터를 한 번에 Prefetching하지 않고, 사용자 경험에 중요한 첫번 째 layout.tsx와 loading.tsx만 Prefetching한다.
import { useRouter } from "next/router";
import { useState } from "react";
export default function PrefetchOnHover() {
const router = useRouter();
const handleMouseEnter = () => {
router.prefetch("/contact");
};
return (
<div>
<h1>Prefetch on Hover</h1>
<button
onMouseEnter={() => router.prefetch("/contact")}
onClick={() => router.push("/contact")}
>
Go to /contact (Prefetch on Hover)
</button>
</div>
);
}
Soft Navigation
네비게이션에서 변경된 세그먼트에 대한 캐시가 재사용되며 서버에 새로운 데이터를 요청한다. 탐색 시 탐색 중인 라우트에 동적 세그먼트가 포함되어 있지 않거나 현재 경로와 동일한 동적 매개변수 있는 경우 Next.js는 Soft Navigation을 사용한다.