목차
Link 컴포넌트
Link는 HTML <a> 태그를 확장하여 경로 간 사전 로드와 클라이언트 측 내비게이션을 제공하는 내장 컴포넌트
Next.js에서 경로 간 이동을 위한 기본적이고 권장되는 방식
사용 방식
import Link from 'next/link'
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>
}
이때 사전 로드란?
사용자가 방문하기 전에 백그라운드에서 경로를 미리 로드하는 방법(자바스크립트 번들 등 미리 다운로드)
(이때 사전 로드는 개발 환경에서는 활성화되지 않으며, 프로덕션 환경에서만 활성화 됨)
1. Link 컴포넌트: 경로가 사용자의 뷰포트에 보이게 되면 자동으로 사전 로드된다.
사전 로드는 페이지가 처음 로드될 때 또는 스크롤을 통해 뷰에 들어올 때 발생합니다.
++부연설명
이때 Link prefetch는 내부적으로 intersectionObserver API를 사용하여 Link가 브라우저 뷰포트 안에 들어오는
순간 prefetch하게 됩니다.
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
console.log('요소가 화면에 보이기 시작했어요!');
}
});
});
const target = document.querySelector('#my-element');
observer.observe(target);
2. router.prefetch(): useRouter 훅을 사용하여 프로그래밍 방식으로 사전 로드 가능하다.
사용 예시
뷰포트 밖에 있어 Link가 자동 prefetch하지 않을 경우
const router = useRouter();
useEffect(() => {
if (user.isLoggedIn) {
router.prefetch('/dashboard');
}
}, [user]);
id로 스크롤하기
새로운 경로로 이동할 때 맨 위로 스크롤하거나 이전 및 다음 탐색으로 위해 스크롤 위치를 유지하는 것
내비게이션 시 특정 id로 스크롤하려면 URL에 #해시 링크를 추가하거나 href prop에 해시 링크를 전달할 수 있다.
Link는 a 요소로 랜더링되기 때문에 가능하다.
<Link href="/dashboard#settings">Settings</Link>
// 출력
<a href="/dashboard#settings">Settings</a>
이때 내부적으로 브라우저 자체 제공 api인 앵커 태그를 이용하는 것이므로 js를 조작하는 것보다 훨씬 더 구현이 쉽다.
스크롤 복원 비활성화
Next.js 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 })
브라우저 api 이용 클라이언트 사용 시
'use client';
import { useEffect } from 'react';
import { usePathname } from 'next/navigation';
export default function ScrollToTop() {
const pathname = usePathname();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
}
redirect 함수
import { redirect } from 'next/navigation'
async function fetchTeam(id: string) {
const res = await fetch('https://...')
if (!res.ok) return undefined
return res.json()
}
export default async function Profile({ params }: { params: { id: string } }) {
const team = await fetchTeam(params.id)
if (!team) {
redirect('/login')
}
// ...
}
- redirect는 기본적으로 307 (임시 리디렉션) 상태 코드를 반환합니다. 서버 액션에서 사용될 때는 303 (다른 페이지 보기)를 반환하며, 이는 POST 요청 결과로 성공 페이지로 리디렉션하는 데 자주 사용됩니다.
- redirect는 내부적으로 오류를 발생시키므로 try/catch 블록 외부에서 호출해야 합니다.
- redirect는 렌더링 프로세스 동안 클라이언트 컴포넌트에서 호출될 수 있지만, 이벤트 핸들러에서는 호출될 수 없습니다. 대신 useRouter 훅을 사용할 수 있습니다.
- redirect는 절대 URL도 허용하며 외부 링크로 리디렉션하는 데 사용할 수 있습니다.
- 렌더링 프로세스 전에 리디렉션하려면 next.config.js 또는 미들웨어를 사용하세요.
++부연 설명
렌더링 전 리다이렉트가 왜 필요하지?
예: 로그인하지 않은 사용자가 /dashboard에 접근했을 때
클라이언트에서 router.push('/login')를 쓰면 로그인 안 된 사람이 잠깐이라도 dashboard를 보게 될 수 있음
Using the native History API
window.history.pushState
// Next.js의 useRouter
const router = useRouter();
router.push('/products?sort=price-asc');
//실제로 내부에서는 다음과 같이 호출
window.history.pushState({}, '', '/products?sort=price-asc');
페이지 전체는 리로드 되지 않고 히스토리에 기록되기 때문에 뒤로 가기가 가능하다.
window.history.replaceState
url은 바꾸지만 히스토리에 추가하지 않기 때문에 뒤로 가기 버튼을 누르면 이전 페이지로 돌아가지 못한다.
Next.js에서는 router.replace()와 동일하다.
- 로그인 성공 후 /login 페이지를 히스토리에 남기지 않도록. 뒤로 가기 눌렀을 때 다시 로그인 화면으로 돌아오면 UX 안 좋음
- 사용자가 자주 검색하는 UI에서 뒤로 가기를 누를 때 검색 결과가 자꾸 바뀌는 걸 방지하고 싶을 때. 즉, URL은 바꾸지만 사용자의 히스토리에는 안 남기는 게 깔끔함.
- /signup?step=3까지 끝나고 나서 다시 돌아가도 step=3 같은 중간 URL이 노출되지 않도록.
라우팅 및 내비게이션 작동 방식
App Router는 라우팅 및 내비게이션에 대해 하이브리드 접근 방식을 사용합니다. 서버에서 애플리케이션 코드는 경로 세그먼트에 의해 자동으로 코드 분할됩니다. 클라이언트에서 Next.js는 경로 세그먼트를 사전 로드하고 캐시합니다. 즉, 사용자가 새 경로로 내비게이션할 때 브라우저가 페이지를 다시 로드하지 않으며 변경된 경로 세그먼트만 다시 렌더링됩니다. 이는 내비게이션 경험과 성능을 향상시킵니다.
1. 코드 분할
코드 분할은 애플리케이션 코드를 더 작은 번들로 나누어 브라우저가 다운로드하고 실행할 수 있게 한다.
이는 전송되는 데이터 양과 각 요청에 대한 실행 시간을 줄여 성능을 향상시킨다.
서버 컴포넌트를 사용하면 애플리케이션 코드가 경로 세그먼트에 의해 자동으로 코드가 분할된다.
이는 현재 경로에 필요한 코드만 내비게이션시 로드 되는 것을 의미한다.
2. prefetching
사전 로드의 내용은 위에서 설명했으므로 넘어가겠습니다.
3. 캐싱
Next.js에는 라우터 캐시라고 불리는 메모리 내 클라이언트 측 캐시가 있습니다. 사용자가 애플리케이션을 탐색할 때 사전 로드된 경로 세그먼트와 방문한 경로의 React 서버 컴포넌트 페이로드가 캐시에 저장됩니다.
이는 내비게이션 시 새로운 서버 요청을 만드는 대신 가능한 한 캐시를 재사용하여 요청 수와 전송되는 데이터 양을 줄여 성능을 향상시킵니다.
++부연 설명
Next.js는 레이아웃, 로딩 상태 및 페이지로 나뉜 경로 세그먼트의 RSC 페이로드를 저장하는 인메모리 클라이언트 측 라우터 캐시를 가지고 있습니다.
사용자가 경로 간에 탐색할 때, Next.js는 방문한 경로 세그먼트를 캐시하고 사용자가 탐색할 가능성이 있는 경로를 prefetch합니다. 이는 즉시 뒤로/앞으로 탐색을 가능하게 하고, 탐색 간 전체 페이지 리로드를 없애며, React 상태 및 브라우저 상태를 유지합니다.
Router Cache를 사용하면:
레이아웃은 캐시되고 탐색 시 재사용됩니다 (partial rendering).
로딩 상태는 캐시되고 탐색 시 재사용됩니다 (instant navigation).
페이지는 기본적으로 캐시되지 않지만, 브라우저의 뒤로 및 앞으로 탐색 중에는 재사용됩니다. 페이지 세그먼트의 캐시를 활성화하려면 실험적 staleTimes 구성 옵션을 사용할 수 있습니다.
4. 부분 랜더링
부분 렌더링은 내비게이션 시 변경된 경로 세그먼트만 클라이언트에서 다시 렌더링되고, 공유된 세그먼트는 유지되는 것을 의미합니다.
예를 들어, 두 형제 경로인 /dashboard/settings와 /dashboard/analytics 간 내비게이션할 때 settings와 analytics 페이지가 렌더링되고, 공유된 dashboard 레이아웃은 유지됩니다.
5. 소프트 내비게이션
브라우저는 페이지 간 내비게이션 시 "하드 내비게이션"을 수행합니다. Next.js App Router는 페이지 간 "소프트 내비게이션"을 가능하게 하여 변경된 경로 세그먼트만 다시 렌더링되도록 합니다(부분 렌더링). 이를 통해 내비게이션 중 클라이언트 React 상태가 유지됩니다.
6. Back and Forward Navigation
뒤로 및 앞으로 내비게이션
기본적으로 Next.js는 뒤로 및 앞으로 내비게이션을 위해 스크롤 위치를 유지하고 라우터 캐시의 경로 세그먼트를 재사용합니다.
'코딩 정보 > NextJs' 카테고리의 다른 글
| [개념부터 Nextjs] Redirecting (6) | 2025.08.09 |
|---|---|
| [개념부터 nextjs] 서버 컴포넌트 (8) | 2025.08.01 |
| [NextJs] 파이어 베이스를 통해 채팅을 구현해보자 (0) | 2025.05.12 |
| [NextJs] msw 세팅 제대로 하기 feat: 서버 컴포넌트 (2) | 2025.04.30 |
| [NextJs] 프로젝트 Sentry 초기 세팅하기 (1) | 2025.04.25 |