[Next.js] Link 컴포넌트를 사용하면 뭐가 좋을까?

Sara Jo·2024년 9월 9일
post-thumbnail

현재 진행하고 있는 프로젝트에서 <Link> 컴포넌트와 useRouter를 함께 사용하고 있는데, 둘의 차이를 제대로 이해하지 못한 채 사용하고 있는 것 같아서 Next.js에서 navigate 할 수 있는 방법들과, 그 중에서도 <Link> 컴포넌트 사용이 가장 권장되는 이유가 무엇인지 공부해보았다.


Routing과 Navigating

먼저, 비슷해보이는 Routing(라우팅)과 Navigating(네비게이팅)이 무엇을 의미하는지 정확히 짚고 넘어가자.

Routing

Routing(라우팅)은, URL 경로에 따라 어떤 컴포넌트나 페이지를 보여줄지 결정하는 과정(URL과 컴포넌트가 매핑되는 방식)이다. 예를 들어, /about URL에 접근했을 때 About 페이지가 렌더링 되도록 설정하는 것이다.
Next.js는 파일 기반 라우팅을 사용하며, 파일 디렉터리 구조에 따라 페이지가 자동으로 경로에 매핑된다.

Navigating(네비게이팅)은 사용자 인터랙션을 통해 발생하는 페이지 전환 과정을 의미한다.예를 들어, /home에서 /about으로 페이지가 전환되는 것을 말한다.
Next.js에서는 <Link> 컴포넌트나 useRouter 훅 등을 통해 네비게이션을 구현한다.


Next.js에서 네비게이션을 구현하는 방법들

Next.js 공식문서에서 소개하고 있는 navigate 방법은 네 가지가 있다.

HTML의 <a> 태그를 확장한 빌트인 컴포넌트로, prefetching 및 클라이언트 측 네비게이션을 지원한다. Next.js에서 navigate하는 가장 기본적이고 권장되는 방법이다.

2. useRouter 훅:

클라이언트 컴포넌트에서 프로그래밍 방식으로 경로를 변경할 때 사용. 버튼 클릭과 같은 이벤트로 경로를 이동할 때 주로 사용된다.

공식문서에서는 특별히 useRouter를 사용해야 하는 경우가 아니라면, <Link> 컴포넌트를 사용하라고 말하고 있다.

3. redirect 함수:

서버 컴포넌트에서 사용하여 서버 측에서 특정 조건에 따라 경로를 변경할 수 있다.

4. 브라우저의 네이티브 History API:

window.history.pushStatewindow.history.replaceState를 통해 페이지 새로고침 없이 브라우저 히스토리 스택을 업데이트할 수 있다.


prefetch가 뭔데?

위의 공식문서 설명에서 <Link> 컴포넌트는 prefetching을 지원한다고 말하고 있다. prefetch가 뭐길래 <Link> 컴포넌트 사용을 권장한다는 걸까?

Next.js의 라우팅과 네비게이션 작동방식

Next.jsApp Router는 라우팅과 내비게이션 처리에 하이브리드 방식(서버+클라이언트)을 사용한다.
서버에서는 애플리케이션 코드가 경로 세그먼트별로 자동으로 코드 분할(code-splitting)되고, 클라이언트에서는 미리 경로 세그먼트를 로드하고 캐싱하여 성능을 최적화한다. 이를 통해, 사용자가 새로운 경로로 navigate하면 브라우저는 페이지를 새로고침하지 않고 변경된 경로 세그먼트만 다시 렌더링하여 네비게이션 경험과 성능을 향상시킨다.

1. 코드 분할 (Code Splitting)

코드 분할은 애플리케이션 코드를 더 작은 번들로 나누어 브라우저가 다운로드 및 실행하는 방식을 말하는데, 이는 각 요청 시 전송되는 데이터 양과 실행 시간을 줄여 성능을 향상시킨다.

Next.js에서 서버 컴포넌트(Server Components)는 경로 세그먼트에 따라 자동으로 코드가 분할된다. 즉, 네비게이션 시 해당 경로에 필요한 코드만 로드된다.

2. 프리페칭 (Prefetching)

프리페칭은 사용자가 방문할 가능성이 있는 경로의 데이터를 미리 가져오는 기능이다. 이는 사용자가 해당 링크를 클릭하기 전에, 백그라운드에서 그 경로의 리소스를 미리 로드해 두는 방식으로 동작한다.

/list 페이지에서 현재 뷰포트에 나타난 Episode 1, Episode 2의 <Link> 경로를 prefetch 해오고 있다.

import Link from "next/link";
import { fetchAllEpisodes } from "@/lib/fetchAllEpisodes";
...

export default async function List() {
  const episodes = await fetchAllEpisodes();

  return (
    <>
      ...
      <div className={styles.container}>
        <h1 className={styles.title}>Season 1</h1>
        <div className={styles.list}>
          {episodes.map((episode) => (
            // Link 컴포넌트 사용
            <Link
              key={episode.id}
              href={`list/${episode.episode}`}
              className={styles.card}
            >
				...
            </Link>
          ))}
        </div>
      </div>
    </>
  );
}

참고: 프리페칭은 개발 모드에서는 동작하지 않고, 프로덕션 모드에서만 활성화된다.


Link 컴포넌트를 사용하면 좋은 점

Next.js에서 <Link> 컴포넌트를 사용하는 것이 권장되는 이유가 바로 이 prefetching 기능에 있다.

1. 사용자 경험 개선

<Link> 컴포넌트는 해당 링크가 사용자의 뷰포트에 나타날 때 자동으로 연결된 경로의 리소스를 미리 로드(prefetch)한다. 사용자가 링크를 클릭하기 전에 백그라운드에서 비동기적으로 필요한 데이터를 미리 준비해 두기 때문에, 클릭 후에는 즉각적인 페이지 전환이 가능해져 더 빠르고 부드러운 사용자 경험을 제공한다.

2. 성능 최적화

코드 분할과 캐싱과 같은 기술과 결합된 prefetching 기능은 네비게이션 시 불필요한 데이터를 전송하지 않고 경로 세그먼트가 필요할 때만 로드한다. 이를 통해 네트워크 사용량을 줄이고, 서버 요청을 최소화하며, 결과적으로 애플리케이션의 성능을 크게 향상시킨다.

3. 서버 리소스 절약

또한, 서버에서 모든 경로를 동시 요청하지 않기 때문에 서버 부하가 줄어드는 장점도 있다. 사용자가 아직 방문하지 않은 경로는 로드되지 않으며, 필요한 시점에만 필요한 데이터가 전송된다. 이는 사용자가 서버로부터 응답을 받는 시간을 줄여 더욱 원활한 경험을 제공한다.

4. 코드 간결성

마지막으로, <Link> 컴포넌트는 단순한 API와 직관적인 사용법을 제공하여 코드를 간결하고 유지보수하기 쉽게 만든다. 특별한 경우를 제외하고는, 복잡한 로직을 추가로 작성할 필요 없이 자동으로 성능 최적화가 가능하다.


추가로, useRouterrouter.prefetch()로도 프리페칭이 가능하지만, <Link> 컴포넌트는 자동으로 프리페칭을 수행하여 개발자가 별도로 신경 쓸 필요가 없다. 또한, 코드가 간결해지고 유지보수가 쉬워진다.



[참고]
https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating
https://youtu.be/5UX23AOqVvM?si=s09CUbszfMUKeNFu

0개의 댓글