Next.js의 라우팅 시스템 - useRouter, Dynamic Routes, 그리고 Pre-fetching

김현중·2025년 3월 1일

연구소

목록 보기
12/34
post-thumbnail

Next.js에서는 몇몇 강력한 라우팅 시스템을 제공합니다. Next.js의 라우팅 관련 주요 개념들을 살펴보겠습니다.

먼저 useRouter를 사용하면서 다음과 같은 문제들을 발견할 수 있습니다.

🐛 useRouter훅 import할 때 만나는 버그

Next.js에서는 먼저 useRouter 훅을 import하여 라우팅 관련 기능을 활용할 수 있습니다. 이때 중요한 점은 import 경로에 따라 다른 동작을 합니다.

// App Router용 (Next.js 13+)
import { useRouter } from 'next/navigation';

// Pages Router용 (기존 방식)
import { useRouter } from 'next/router';

여기서 App Router와 Pages Router의 방식은 호환되지 않으므로, 사용 중인 라우팅 방식과 Next.js 버전에 맞는 import 경로를 사용합니다.

🐛 콘솔에서 router가 두 번 출력되는 현상

이건 버그는 아니지만

const router = useRouter();
console.log(router);

위 코드를 실행하면 특정 상황에 console에 router 객체가 두 번 출력되는 것을 볼 수 있습니다. 이는 Next.js가 쿼리스트링을 읽는 과정에서 컴포넌트를 한 번 더 렌더링하기 때문입니다. 이럴 때에는 두 번째 console.log()에만 쿼리스트링에 대한 정보가 담겨있습니다.



🤸‍♂️ 다이나믹 라우트(Dynamic Routes)

Next.js는 다양한 형태의 동적 라우팅을 지원합니다. 여기선 두 가지 Catch All Segments 방식과 Optional Catch All Segments 방식을 연구해보겠습니다.

Catch All Segments

URL이 /CAS/123/456/789...와 같이 여러 ID 값을 포함할 경우, 파일을 계속 중첩해서 만들지 않고, /CAS/[...id].tsx로 지정하면 모든 ID 값을 배열 형태로 받을 수 있습니다.

// /CAS/[...id].tsx
const CASPage = () => {
  const router = useRouter();
  console.log(router.query.id); // ['123', '456', '789', ... ]
  
  return <> ... </>;
};

이러한 방식을 catch all segment라고 부르며, 특정 경로 이후의 모든 세그먼트를 캡쳐합니다.

Optional Catch All Segments

만약 /OCAS 와 같이 index.tsx가 없는 URL에서도 같은 페이지를 보여주고 싶다면, 파일명을 /OCAS/[[...id]].tsx와 같이 이중 대괄호로 감싸면 됩니다.

// /OCAS/[[...id]].tsx
const OCASPage = () =>{
  const router = useRouter();
  console.log(router.query.id); // id가 없으면 undefined, 있으면 배열 형태
  
  return <> ... </>;
};

이러한 방식은 optional catch all segment라고 부릅니다.



🚀 페이지 이동 방식

Next.js에서는 페이지 이동 방식이 여러 가지 있습니다.

1. HTML <a> 태그

<a href="/about">About</a>

이 방식은 서버에 새로운 페이지를 요청하는 방식으로, 클라이언트 사이드 렌더링이 아닌 전통적인 페이지 이동 방식입니다.

import Link from 'next/link';

<Link href='/about'>About</Link>

<Link>컴포넌트는 클라이언트 사이드 렌더링 방식으로 페이지를 이동시키며, SPA처럼 동작합니다.

3. 프로그래매틱 페이지 이동

const router = useRouter();

// 이벤트 핸들러 등에서 사용
const handleClick = () => {
  router.push('/about');
};

router.push() 메서드도 CSR 방식으로 페이지를 이동시킵니다.


🌱 Pre-fetching

여기서 중요한 Next.js의 핵심 기능 중 하나는 'pre-fetching' 입니다. 이는 사용자가 현재 페이지에서 이동할 가능성이 있는 페이지를 사전에 불러놓는 기능입니다.

✨pre-fetching의 필요성

Next.js는 번들링 시 현재 페이지에 필요한 JS 번들만 전달합니다. 모든 페이지의 번들을 한꺼번에 전달하면 초기 로딩 시간이 길어지고 TTI가 늦어지기 때문입니다. 그에 반해 현재 페이지에 필요한 번들만 있으면, 사용자가 페이지를 이동할 때마다 새 번들을 받아야 하는 비효율이 발생합니다. 이 문제를 해결하기 위해서 Next.js는 pre-fetching 기능을 제공합니다.

<Link> 컴포넌트는 기본적으로 pre-fetching을 수행합니다. 이를 통해 사용자가 링크를 클릭하면 이미 필요한 리소스가 로드되어 있어 빠른 페이지 전환이 가능합니다.

// 기본적으로 pre-fetching이 활성화됨
<Link href="/about">About</Link>

// pre-fetching을 비활성화하려면
<Link href="/about" prefetch={false}>About</Link>

프로그래매틱 Pre-fetching

router.push()와 같은 프로그래매틱 페이지 이동에는 기본적으로 pre-fetching이 적용되지 않기 때문에 컴포넌트가 마운트 되었을 때 router.prefetch() 메서드 등으로 pre-fetching을 수행할 수 있습니다.

useEffect(() => {
  router.prefetch('/about');
}, []);

이렇게 하면 컴포넌트가 마운트될 때 '/about' 페이지에 대한 pre-fetching이 수행됩니다.

🚨 주의사항

Pre-fetching은 개발 모드에서 확인할 수 없습니다. npm run build 후 npm run start로 프로덕션 환경에서 확인해야 합니다.

profile
박수 받는 사람이 되고 싶어서 항상 노력합니다.

0개의 댓글