2. Linking 및 Navigating
- Link 컴포넌트 사용
- useRouter hook 사용(클라이언트 사이드)
- redirect 사용(서버 사이드)
- History API 사용
1️⃣ Link 컴포넌트
- prefetching (사용자가 경로를 방문하기 전 백그라운드에서 경로를 미리 로드하는 방식) 및 라우트 간 client side 탐색을 제공하는 HTML a태그의 확장 버전
- Next.js에서 라우트 간 탐색을 진행하는 가장 기본적이고 권장되는 방식
- API
- href (필수, type: String or Object)
- scroll (기본 true, 브라우저가 뒤 및 앞으로 탐색을 처리할 때 스크롤 위치를 유지, type: Boolean)
- replace (기본값 false, 브라우저의 history stack에 새 url을 추가하는 대신 현재 기록 state를 변경, type: Boolean)
- prefetch (기본 null,
<Link/>
구성 요소가 사용자의 뷰포트에 들어갈 때 발생. href로 연결된 데이터를 백그라운드에서 미리 가져오고 로드해서 클라이언트 측 탐색 성능을 향상시킨다. 프로덕션에서만 사용 가능한 기능, type: Boolean or null)
2️⃣ useRouter() 훅
클라이언트 구성요소 useRouter에서 경로를 프로그래밍 방식으로 변경 가능
"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()를 꼭 사용할 이유가 없다면, 라우트 간 탐색 진행 시 Link를 사용하는 것이 권장됨
API
router.push(href: string, { scroll: boolean })
: 제공된 경로로 클라이언트 측 탐색 진행, 브라우저 히스토리 스택에 새 경로가 쌓인다.router.replace(href: string, { scroll: boolean })
: 브라우저 히스토리 스택에 새 경로가 쌓이지 않고, 제공된 경로로 클라이언트 측 탐색이 진행된다router.refresh()
: 현재 라우트를 새로고침한다.
즉, 서버에 새로운 요청을 보내고 데이터를 다시 가져와서 서버 컴포넌트를 다시 렌더링합니다. 이 과정에서 클라이언트 측의 React 상태(useState 등)나 브라우저 상태(예: 스크롤 위치) 는 유지된다.
즉, 서버에서 새로운 데이터를 받아 업데이트하지만, 영향을 받지 않는 클라이언트 측 상태는 그대로 유지된다.router.prefetch(href: string)
: 제공된 경로를 미리 설정하여 클라이언트 측 전환을 더 빠르게 한다.router.back()
: 브라우저 히스토리 스택에서 이전 경로로 다시 이동router.forward()
: 브라우저 히스토리 스택에서 다음 경로로 이동
❗ 알아두면 좋을 내용
♋ Next.js에서 router.push
, <Link> 컴포넌트
, 그리고 refresh()
와 관련된 보안 및 동작 방식에 대한 설명
1️⃣ router.push / router.replace의 보안 문제
router.push
또는 router.replace
에 검증되지 않은 URL을 직접 넣으면 XSS(크로스 사이트 스크립팅) 공격에 취약할 수 있다.
const userInput = "javascript:alert('XSS')";
router.push(userInput); // ❌ 보안 취약점 발생 가능
예를 들어, 위 코드와 같이 사용자 입력을 그대로 사용하면, router.push(userInput)
이 실행되고 javascript: URL 스킴이 실행될 수도 있고 이로 인해 악성 코드가 동작하게 될 수 있다.
✅ 해결 방법
사용자 입력을 그대로 사용하지 말고, 신뢰할 수 있는 경로인지 검증하거나 encodeURIComponent()
같은 방법을 사용한다.
2️⃣ <Link>
의 자동 프리페치<Link>
컴포넌트는 화면에 보이면 해당 경로를 자동으로 미리 가져온다(prefetch).
즉, 사용자가 해당 링크를 클릭하기 전에 미리 데이터를 가져와서 페이지 전환 속도를 높이는 역할을 한다.
예를 들어
<Link href="/dashboard">Go to Dashboard</Link>
위 코드에서 <Link>
가 화면에 나타나면 Next.js가 자동으로 /dashboard
페이지 데이터를 미리 가져오게 된다.
3️⃣ refresh()
의 동작 방식refresh()
를 사용하면 서버에서 데이터를 다시 가져오지만, 캐싱된 fetch 요청 데이터가 있으면 같은 응답이 나올 수도 있다.
또한 쿠키나 헤더 같은 동적 API 값이 변하면 응답이 달라질 수도 있다.
import { refresh } from "next/navigation";
async function handleRefresh() {
refresh(); // 서버 데이터를 다시 불러옴
}
✅ 해결 방법
cache: "no-store"
옵션을 사용하여 항상 최신 데이터를 가져온다.revalidatePath()
같은 API를 사용하여 특정 페이지만 다시 갱신한다.
요약
- router.push와 router.replace에 검증되지 않은 URL을 직접 넣지 마라 (XSS 공격 위험).
<Link>
컴포넌트는 화면에 나타나면 자동으로 미리 데이터를 가져온다 (퍼포먼스 최적화).refresh()
는 캐시된 데이터를 그대로 반환할 수도 있으며, 쿠키나 헤더 값이 변하면 응답도 달라질 수 있다.
3️⃣ next/navigation에서 가져오기 (redirect 함수)
redirect 함수
- 서버 컴포넌트에서 사용 가능
- 리다이렉트는 서버 액션, 서버 컴포넌트, 라우트 핸들러에서 사용된다
redirect(path, type)
- type : Server Action에서 동작x (기본
push
), Server Action 제외 다른 곳에선 기본이replace
❗ 알아두면 좋을 내용
- redirect는 기본적으로 307 (Temporary Redirect) 상태 코드를 반환한다.하지만 Server Action에서 사용될 경우, 일반적으로 POST 요청의 성공 페이지로 리디렉션할 때 사용되는 303 (See Other) 상태 코드를 반환한다.
- redirect는 내부적으로 오류를 발생시키므로 try/catch 블록 밖에서 호출해야 한다.
- Client Component에서 렌더링 과정 중에는 호출할 수 있지만, 이벤트 핸들러에서는 사용할 수 없다 → 이벤트 핸들러에서는 대신 useRouter 훅을 사용할 수 있다.
- 절대 URL을 포함한 외부 링크로도 리디렉션이 가능하다.
- 렌더링 전에 리디렉션하려면
next.config.js
또는 Middleware를 사용해야 한다.
4️⃣ History API
Next.js에서는 페이지를 새로고침하지 않고 브라우저의 기록 스택을 업데이트하기 위해 기본적인 window.history.pushState
및 window.history.replaceState
메서드를 사용할 수 있다.pushState
및 replaceState
호출은 Next.js 라우터와 통합되어 usePathname
및 useSearchParams
와 동기화 가능하다.
window.history.pushState
: 브라우저 히스토리스택에 새 엔트리 추가. 뒤로 가기 가능window.history.replaceState
: 최근 엔트리를 새 엔트리로 교체, 뒤로 가기 불가능window.history.replaceState(null, '', newPath)
→ 이렇게 씀
라우팅 및 네비게이션 동작 방식
앱라우터에서는 라우팅 및 네비게이션을 위해 하이브리드 접근 방식
이용
- 서버에서 애플리케이션 코드는 경로 세그먼트별로 자동 코드 분할됨 / 클라이언트에서는 경로 세그먼트를 prefetch 및 캐시함
- 즉, 사용자가 새 경로로 이동할 때 브라우저는 페이지를 다시 로드하지 않고 경로 세그먼트만 리렌더링하여 탐색 경험과 성능을 향상시킨다.
✳ 1. Code Splitting
- 애플리케이션코드를 더 작은 번들로 분할하여 브라우저에서 다운 및 실행 가능 → 요청에 대한 데이터 전송량 및 실행시간 감소
- 서버 컴포넌트에서는, 애플리케이션 코드를 경로 세그먼트별로 자동 코드분할 가능 → 현재 경로에 필요한 코드만 네비게이션에 로드됨
✳ 2. Prefetching
- 사용자가 경로방문 전 백그라운드에서 미리 경로를 로드하는 것.
<Link>
컴포넌트,router.prefetch()
를 이용해 경로를 미리 fetch 할 수 있다.
✳ 3. Caching
- Router Cache: 인메모리 클라이언트측 캐시 (in-memory client-side cache)
- 사용자가 앱을 탐색할 때, 프리패치된 route segments와 방문한 경로의 react server component payload가 캐시에 저장된다 → 탐색 시 서버에 새로운 요청을 하는 대신, 캐시를 최대한 재사용하여 요청 수와 전송되는 데이터 수를 줄여 성능을 향상시킨다.
✳ 4. Partial Rendering
탐색 중에 변경되는 route segments만 클라이언트에서 리렌더링되고, 공유 세그먼트(shared segments)는 보존된다.
예를 들어서 dashboard/settings
와 dashboard/analytics
둘을 탐색할 때, settings
페이지는 언마운트되고, analytics
페이지는 새로운 상태로 마운트된다. 그리고 dashboard 레이아웃은 그대로 유지됨.
이러한 동작은 같은 동적 세그먼트, 예를 들어 /blog/[slug]/page
에서 두 경로 사이에도 존재한다. (즉, /blog/first
에서 /blog/second
로 이동할 때)
부분 렌더링이 없다면 각각의 navigation은 전체 페이지를 리렌더링해야 된다. 변경되는 부분만 렌더링하면, 전송되는 데이터 양과 실행 시간이 줄어들어 성능이 향상된다.
✳ 5. soft navigation
브라우저는 페이지 간 이동 시 "강제 이동(hard navigation)"을 수행한다. Next.js 앱 라우터는 페이지 간에 "부드러운 이동(soft navigation)"을 가능하게 하여 변경된 경로 세그먼트만 다시 렌더링(부분 렌더링)하도록 한다. 이를 통해 클라이언트 React 상태가 탐색 중에도 유지된다.
✳ 6. Back and Forward Navigation
페이지를 앞뒤로 탐색할 수 있도록, 스크롤 위치를 유지하고 라우터 캐시에서 경로 세그먼트를 재사용한다.
✳ 7. pages/
와 app/
사이의 라우팅
1️⃣ pages/
→ app/
이동 시 라우팅 동작
Next.js 14에서는 pages/
와 app/
을 동시에 사용 가능하다.
즉, 기존 pages/
기반 라우팅을 유지하면서 일부 페이지를 app/
으로 점진적으로 전환할 수 있다.
이 과정에서 Next.js는 클라이언트 라우터 필터(client router filter)를 활용하여 어떤 요청이 app/에 속하는지 판단한다.
2️⃣ 클라이언트 라우터 필터 (Client Router Filter)
Next.js는 성능 최적화를 위해 모든 app/ 경로를 클라이언트로 전달하는 대신, 확률적(probabilistic) 방식을 사용하여 app/
페이지 여부를 판단한다.
이러한 방식은 메모리를 덜 사용하지만, 확률적으로 잘못된 판단(false positive)이 발생할 가능성이 있다.
- False Positive (오탐):
pages/
에 속한 경로인데, Next.js가app/
에 속한 것으로 잘못 판단하는 경우 - 기본적으로 0.01% 확률로 발생하도록 설정되어 있음
- 확률을 더 낮추면(= 더 정확하게 만들면), 필터 크기가 커져 클라이언트 번들 크기가 증가
3️⃣ next.config.js에서 오탐률 조정
확률을 조정할 수 있는 옵션: experimental.clientRouterFilterAllowedRate
// next.config.js
module.exports = {
experimental: {
clientRouterFilterAllowedRate: 0.001, // 오탐 확률을 0.001%로 낮춤
},
};
- 값을 낮추면(false positive 확률 ↓):
→ 더 정확하게 app/ 페이지를 판별하지만, 클라이언트 번들 크기가 증가 - 값을 높이면(false positive 확률 ↑):
→ 클라이언트 번들은 가벼워지지만, app/ 경로 판단 오류가 더 자주 발생
4️⃣ ⚠️주의할 점
- 이 기능은 실험적(experimental) 옵션이므로, 향후 변경될 가능성이 있음.
- 무조건 낮추는 것이 좋은 것이 아님 → 번들 크기 증가와의 균형을 고려해야 함.
app/
으로 완전히 마이그레이션하면 이 옵션이 필요 없어짐.
출처
https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating
Routing: Linking and Navigating | Next.js
Learn how navigation works in Next.js, and how to use the Link Component and `useRouter` hook.
nextjs.org
'웹 프로그래밍 > Next.js' 카테고리의 다른 글
[Next.js 공식문서 정리] Routing : 05. Redirecting (0) | 2025.03.29 |
---|---|
[Next.js 공식문서 정리] Routing : 04. Loading UI and Streaming (2) | 2025.03.29 |
[Next.js 공식문서 정리] Routing : 03. Error Handling (0) | 2025.03.29 |
[Next.js 공식문서 정리] Routing : 01. Layouts and Templates (0) | 2025.03.28 |
Learn Next.js 공식문서 공부 내용 정리 (1) | 2024.12.22 |
[유데미 | Maximilian] Next.js 강의 내용 정리 (섹션 1: 시작하기) (0) | 2024.05.19 |