[번역] Next.js13 App Router - Routing - Linking and Navigating

최영호·2023년 7월 28일
1

On this page

Next.js 라우터는 서버 중심 라우팅클라이언트 사이드 네비게이션을 사용하고 있습니다.
이 기능을 통해 바로 스테이트를 로딩하고 동시성 렌더링을 지원할 수 있습니다.
이는 네비게이션이 클라이언트 사이드 스테이트를 유지할 수 있고 비싼 연산에 속하는 리렌더링을 피할 수 있고 중간에 렌더링 프로세스를 가로챌 수 있기 때문에 레이스 컨디션을 발생 시키지 않습니다.

라우트 사이에 네비게이션을 할 수 있는 방법에는 2가지 정도 있습니다.

이번 문서에선 어떻게 <Link> 컴포넌트와 useRouter() 훅을 사용하는지 알아볼 것이며 어떻게 네비게이션이 동작하는지 자세히 알아봅니다.

<Link> 컴포넌트는 HTML의 <a> 태그를 확장시킨 리액트 컴포넌트로 라우트 사이에 프리패치와 클라이언트 사이드 네비게이션을 처리할 수 있도록 도와줍니다.
해당 컴포넌트를 사용하는 것이 Next.js에서 라우트 사이에 네비게이션을 할 수 있는 가장 기본적인 방법입니다.

<Link> 컴포넌트를 사용하기 위해선 next/link 패키지를 import 하고 컴포넌트에 href 프롭을 전달하면 됩니다.

import Link from 'next/link'
 
export default function Page() {
  return <Link href="/dashboard">Dashboard</Link>
}

<Link> 컴포넌트에 전달할 수 있는 부가적인 옵션 프롭도 존재합니다.
더 자세한 정보는 API Reference 페이지에서 확인하세요.

Examples

Linking to Dynamic Segments

다이나믹 세그먼트를 링크할 때 템플릿 리터럴과 템플릿 인터폴레이션을 사용하여 링크 리스트를 만들어 낼 수 있습니다.
예를 들어 블로그 포스트의 리스트를 만들기 위해선 아래와 같이 작성하면 됩니다.

import Link from 'next/link'
 
export default function PostList({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}

usePathname() 훅을 사용하여 현재 링크가 액티브 상태인지 확인할 수 있습니다.
예를 들어 액티브 상태의 링크에 클래스를 추가하고 싶다면 링크의 href 값이 현재 pathname 과 일치하는지 체크해 보면 됩니다.

'use client'
 
import { usePathname } from 'next/navigation'
import Link from 'next/link'
 
export function Navigation({ navLinks }) {
  const pathname = usePathname()
 
  return (
    <>
      {navLinks.map((link) => {
        const isActive = pathname.startsWith(link.href)
 
        return (
          <Link
            className={isActive ? 'text-blue' : 'text-black'}
            href={link.href}
            key={link.name}
          >
            {link.name}
          </Link>
        )
      })}
    </>
  )
}

Scrolling to an id

<Link> 컴포넌트의 기본 동작 방식은 변경 된 라우트 세그먼트의 최상단으로 스크롤 되는 것입니다.
href 값에 id 값이 명시되어 있다면 평범한 <a> 태그 처럼 해당하는 id 값이 담긴 엘리먼트로 스크롤 됩니다.

useRouter() Hook

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>
  )
}

useRouter 훅은 push() , refresh() 와 같은 함수들을 제공합니다.
더 많은 정보를 얻고 싶다면 API reference 페이지에서 확인하세요.

추천 사항:
특별한 요구사항으로 useRouter 를 사용해야 하는게 아니라면 <Link> 컴포넌트를 사용하여 네비게이션을 처리하세요.

How Navigation Works

  • <Link> 컴포넌트 혹은 router.push() 를 호출하는 경우 라우터 변경이 이루어집니다.
  • 라우터는 브라우저 주소창의 URL을 업데이트 합니다.
  • 라우터는 클라이언트 사이드 캐시를 통해 변경 되지 않은 세그먼트를 재사용하여 작업을 최적화합니다. 이는 부분 렌더링이라고도 알려져 있습니다.
  • 소프트 네비게이션을 할 수 있는 조건이 갖추어진다면 라우터는 서버로 부터 새로운 세그먼트를 받아오지 않고 캐시에서 가져오게 됩니다. 만약 조건이 갖추어지지 않았다면 라우터는 하드 네비게이션을 실행시켜 서버로부터 서버 컴포넌트 페이로드를 받아오게 됩니다.
  • 만약 하드 네비게이션이 실행 되었다면 페이로드를 패치하는 동안 로딩UI가 보여지게 됩니다.
  • 라우터는 클라이언트에서 새로운 세그먼트를 렌더링하기 위해 캐시 된 세그먼트를 쓰거나 새로운 페이로드를 받아와 사용합니다.

Client-side Caching of Rendered Server Components

참고 사항:
클라이언트 사이드 캐시는 서버 사이드 Next.js HTTP 캐시와는 다릅니다.

새롭게 도입 된 라우터는 서버 컴포넌트의 페이로드의 렌더링 결과물을 저장하고 있는 인메모리 클라이언트 사이드 캐시를 가지고 있습니다.
캐시는 라우트 세그먼트에 따라 구분되며 어느 레벨에서도 재검증을 요청할 수 있고 동시성 렌더링 과정 중에 일관성을 유지할 수 있습니다.

유저가 어플리케이션을 네비게이션 할 때 라우터는 이전에 패치받은 세그먼트의 페이로드를 저장하고 캐시에서 세그먼트를 프리패치합니다.

이는 특정 케이스에선 라우터가 서버에 새로운 요청을 보내지 않고 캐시를 재사용할 수 있다는 것입니다.
이 방식은 불필요하게 데이터를 다시 패치하고 리렌더링 하지 않기 때문에 퍼포먼스를 향상시킬 수 있습니다.

Invalidating the Cache

서버 액션은 주소(revalidatePath) 혹은 캐시 태그(revalidateTag)에 따라 온디맨드로 데이터를 재검증할 수 있습니다.

Prefetching

프리패치는 방문하기 전에 미리 백그라운드에서 라우트를 로딩하는 방법을 말합니다.
프리패치한 라우트의 렌더링 결과물은 라우터의 클라이언트 사이드 캐시에 추가 됩니다.
이 방식을 사용하여 프리패치 한 라우트로 이동하는게 순식간에 일어나는 것 처럼 보이게 됩니다.

기본적으로 라우트는 <Link> 컴포넌트를 사용하고 있으면 뷰포트에서 보여졌을 때 프리패치 됩니다.
이는 초기 페이지 로딩이나 스크롤을 통해 발생할 수 있습니다.
라우트는 useRouter()prefetch 메소드를 통해 프로그래밍적으로 프리패치 될 수 있습니다.

Static and Dynamic Routes:

  • 라우트가 스태틱하다면 해당 라우트 세그먼트에 필요한 모든 서버 컴포넌트 페이로드는 프리패치 됩니다.
  • 라우트가 다이나믹하다면 첫 loading.js 파일을 마주치기 전 공유 레이아웃까지가 프리패치 됩니다. 이는 다이나믹하게 라우트 전체를 프리패치할때 발생하는 비용을 줄여주고 다이나믹 라우트에 바로 로딩 스테이트를 사용할 수 있게 해줍니다.

참고 사항:

  • 프리패치는 프로덕션 모드에서만 사용할 수 있습니다.
  • 프리패치는 <Link> 컴포넌트에 prefetch={false} 를 전달하여 비활성화 시킬 수 있습니다.

Soft Navigation

네비게이션에서 변경 된 세그먼트의 캐시는 존재한다면 재사용 되고 서버에 요청을 보내지 않습니다.

Conditions for Soft Navigation

네비게이션에서 Next.js는 방문할 라우트가 프리패치 되어 있고 다이나믹 세그먼트를 포함하지 않거나 현재 라우트와 동일한 다이나믹 파라미터를 가지고 있다면 소프트 네비게이션을 사용합니다.

예를 들어 다이나믹 세그먼트인 [team] 을 포함하는 /dashboard/[team]/* 라우트를 생각해 봅시다
/dashboard/[team]/* 아래의 캐시 처리 된 세그먼트는 [team] 파라미터가 변경 될 때만 재검증 처리 될 것입니다.

  • /dashboard/team-red/* 에서 /dashboard/team-red/* 로의 네비게이션은 소프트 네비게이션으로 처리 됩니다.
  • /dashboard/team-red/* 에서 /dashboard/team-blue/* 로의 네비게이션은 하드 네비게이션으로 처리 됩니다.

Hard Navigation

캐시는 무효화 처리 되고 서버는 데이터를 패치하며 변경 된 세그먼트에 맞게 리렌더링 되는 네비게이션 방법입니다.

Back/Forward Navigation

Back/Forward Navigation (popstate event) 는 소프트 네비게이션 방식으러 처리 됩니다.
이는 클라이언트 사이드 캐시가 재사용 되고 네비게이션은 순식간에 처리됩니다.

Focus and Scroll Management

기본적으로 Next.js는 네비게이션에서 변경 되는 세그먼트로 포커스가 맞춰지고 뷰포트에 들어올 수 있도록 스크롤 됩니다.

profile
무친 프론트엔드 개발자를 꿈꾸며...

0개의 댓글