[ Routing ] Linking and Navigating

차차·2023년 5월 17일
0

Next Docs

목록 보기
5/34
post-thumbnail

Next.js 라우터는 server-centric routingclient-side navigation을 사용한다. 이는 즉각적인 로딩 상태와 동시 렌더링을 지원한다. 내비게이션이 클라이언트 측 상태를 유지하고 비용이 많이 드는 리렌더링을 피하며, 중단 가능하며 race condition을 발생시키지 않는다는 것을 의미한다.


라우트 간 이동하는 두 가지 방법이 있다.
  • <Link> Component
  • useRouter Hook


Link 컴포넌트

<Link>는 HTML <a> 요소를 확장하여 라우트 간 사전 로딩과 클라이언트 측 내비게이션을 제공하는 React 컴포넌트이다. Next.js에서 라우트 간 이동하는 주요한 방법이다.


<Link>를 사용하려면 next/link에서 import하고 컴포넌트에 href속성을 전달하면 된다.

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

동적 세그먼트 연결

동적 세그먼트에 연결할 때, 템플릿 리터럴(``)과 보간(${})을 사용하여 링크 목록을 생성할 수 있다.

예를 들어, 블로그 글 목록을 생성하려면 다음과 같이 할 수 있다.

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와 일치하는지 확인하여 활성 링크에 클래스를 추가할 수 있다.

'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>
        );
      })}
    </>
  );
}

id로 스크롤

<Link>의 기본 동작은 변경된 경로 세그먼트의 맨 위로 스크롤하는 것이다. href에 정의된 id가 있는 경우, 일반적인 <a> 태그와 비슷하게 해당 id로 스크롤된다.

경로 세그먼트의 맨 위로 스크롤되는 것을 방지하려면 scroll={false}를 설정하고 href에 해시된 id를 추가한다.

<Link href="/#hashid" scroll={false}>
  Scroll to specific id.
</Link>


useRouter( )

useRouter 훅을 사용하면 클라이언트 컴포넌트 내에서 프로그래밍 방식으로 경로를 변경할 수 있다.


useRouter를 사용하려면 next/navigation에서 import하고 클라이언트 컴포넌트 내에서 해당 훅을 호출하면 된다.

'use client';
 
import { useRouter } from 'next/navigation';
 
export default function Page() {
  const router = useRouter();
 
  return (
		// '/dashboard'로 이동
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  );
}

이외에도 useRouter()push(), refresh() 등의 메소드를 제공한다.



네비게이션 작동 방식

  1. <Link>를 사용하거나 router.push()를 호출하여 경로 전환이 시작된다.
  2. 라우터는 브라우저 주소 표시줄의 URL을 업데이트한다.
  3. 라우터는 변경되지 않은 세그먼트(예: 공유 레이아웃)를 클라이언트 캐시에서 다시 사용하여 불필요한 작업을 피한다. 이것을 부분 렌더링(partial rendering)이라고도 한다.
  4. 소프트 네비게이션 조건을 충족하면 라우터는 서버가 아닌 캐시에서 새로운 세그먼트를 가져온다. 그렇지 않으면 라우터는 하드 네비게이션을 수행하고 서버에서 서버 컴포넌트 페이로드를 가져온다.
  5. 로딩 UI가 생성된 경우, 페이로드를 가져오는 동안 서버에서 로딩 UI가 표시된다.
  6. 라우터는 캐시된 또는 새로운 페이로드를 사용하여 클라이언트에서 새로운 세그먼트를 렌더링한다.

클라이언트 측에서 렌더링된 서버 컴포넌트의 캐싱

이 클라이언트 측 캐시는 서버 측 Next.js HTTP 캐시와 다르다.

새로운 라우터에는 서버 컴포넌트(페이로드)의 렌더링 결과를 저장하는 인메모리 클라이언트 측 캐시가 있다. 이 캐시는 경로 세그먼트별로 분할되어 임의의 레벨에서 무효화가 가능하며, 동시에 렌더링되는 컴포넌트 간 일관성을 보장한다.

사용자가 앱을 탐색하는 동안, 라우터는 이전에 가져온 세그먼트의 페이로드와 사전로드된 세그먼트의 페이로드를 캐시에 저장한다.

이는 특정 경우에 라우터가 새로운 서버 요청을 하지 않고 캐시를 재사용할 수 있다는 것을 의미한다. 이는 데이터를 다시 가져오거나 컴포넌트를 불필요하게 다시 렌더링하는 것을 피함으로써 성능을 향상시킨다.


캐시 무효화

서버 액션은 경로(revalidatePath) 또는 캐시 태그(revalidateTag)별로 필요에 따라 데이터를 다시 유효성 검사하는 데 사용할 수 있다.


사전 로드

사전로드는 방문하기 전에 백그라운드에서 경로를 미리 로드하는 방법이다. 사전로드된 경로의 렌더링 결과는 라우터의 클라이언트 측 캐시에 추가된다. 이를 통해 사전로드된 경로로의 이동이 거의 빠르게 이루어진다.

기본적으로 <Link> 컴포넌트를 사용할 때 뷰포트에 표시되는 순간 경로가 사전로드된다. 이는 페이지가 처음 로드되거나 스크롤하는 경우에 발생할 수 있다. 또한 useRouter() 훅의 prefetch 메서드를 사용하여 프로그래밍 방식으로 경로를 사전로드할 수도 있다.


💡 정적 및 동적 경로

  • 경로가 정적인 경우, 경로 세그먼트의 모든 서버 컴포넌트 페이로드가 사전로드된다.
  • 경로가 동적인 경우, 첫 번째 공유 레이아웃부터 첫 번째 loading.js 파일까지의 페이로드가 사전로드된다. 이는 경로 전체를 동적으로 사전로드하는 비용을 줄이고 동적 경로에 대한 즉시 로딩 상태를 제공한다.

💡 알아두면 좋은 점

  • 사전로드는 프로덕션 환경에서만 활성화된다.
  • <Link>prefetch={false}를 전달하여 사전로드를 비활성화할 수 있다.

Hard Navigation

네비게이션 시 캐시가 무효화되고 서버가 데이터를 다시 가져와 변경된 세그먼트를 다시 렌더링한다.


Soft Navigation

네비게이션 시 변경된 세그먼트의 캐시가 재사용되고 (캐시가 존재하는 경우) 데이터를 위해 새로운 서버 요청이 발생하지 않는다.


💡 소프트 네비게이션의 조건

네비게이션 시 Next.js는 소프트 네비게이션을 사용한다. 이는 네비게이션하려는 경로가 사전로드된 경우이며, 동적 세그먼트를 포함하지 않거나 현재 경로와 동일한 동적 매개변수를 가지는 경우이다.


👇  예를 들어, 다음과 같은 동적 [team] 세그먼트를 포함하는 경로를 고려해보자.

  • /dashboard/[team]/** 아래에 캐시된 세그먼트는 [team] 매개변수가 변경될 때만 무효화된다.
  1. /dashboard/team-red/* 에서 /dashboard/team-red/* 로 이동하는 경우, 소프트 네비게이션으로 처리된다.
  2. /dashboard/team-red/* 에서 /dashboard/team-blue/* 로 이동하는 경우, 하드 네비게이션으로 처리된다.

뒤로 / 앞으로 이동 네비게이션

뒤로 및 앞으로 이동 네비게이션(popstate 이벤트)은 소프트 네비게이션 동작을 가지고 있다. 이는 클라이언트 측 캐시가 재사용되고 네비게이션이 거의 즉시 이루어진다는 것을 의미한다.


포커스 및 스크롤 관리

기본적으로 Next.js는 네비게이션 시 변경된 세그먼트에 포커스를 설정하고 스크롤을 뷰에 맞춘다.


[출처]
https://nextjs.org/docs/app/building-your-application/routing/linking-and-navigating

profile
나는야 프린이

0개의 댓글