React&Next.js

[Next.js] Linking과 Navigating 알아보기

jjin502 2024. 7. 4. 20:47

Linking 그리고 Navigating

Next.js 라우터는 클라이언트 사이드 Navigation을 위한 서버 중심 라우팅을 사용한다.

동시에 렌더링을 하거나 즉시 로딩이 가능하다.

 

이는 Navigation이 클라이언트 사이드 상태를 유지하며 

비용이 많이 드는 재랜더링을 피할 수 있고, 중단이 가능하다는 것을 의미한다.

 

<Link> 컴포넌트

react의 <a> 태그를 확장하여 프리패칭과 라우트 간에 클라이언트 사이드 네비게이션을 제공한다.

라우트 간에 이동하는 주요 방법이다.

 

next/link로 부터 import해서 사용할 수 있다.

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

 

a태그와 같이 herf속성을 사용하면 된다.

 

동적 페이지 링크로 연결하기

현재 제작 중인 기술 블로그의 일부 코드다.

글 목록 페이지에 글 요소 하나로 이동하는 방법이다.

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

 

링크를 클릭하면 /blog/${post.slug} 링크로 이동하면서 해당 글을 자세하게 확인할 수 있다.

 

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

 

  • router.push(herf : string) : 제공된 라우트로 클라이언트 사이드 네비게이션 수행하고 브라우저 히스토리 스택에 새 항목을 추가한다.
  • router.replace(herf : string) : 제공된 라우트로 클라이언트 사이드 네비게이션 수행하지만, 브라우저 히스토리 스택에 새 항목을 추가하지 않는다.
  • router.refresh() : 현재 라우트를 새로 고침함. 서버에 새 요청을 만들고, 데이터 요청을 다시 가져오며 서버컴포넌트를 다시 렌더링한다. 클라이언트는 영향을 받지 않는 클라이언트 측 React 혹은 브라우저 상태를 잃지 않고, React 서버 컴포넌트 페이로드를 병합함.
  • router.prefetch(href: string) : 더 빠른 클라이언트 사이드 전환을 위해 제공된 라우트를 프리패칭한다.
  • router.back() : 소프트 네비게이션 사용, 브라우저 히스토리 스택에서 이전 라우트로 돌아감
  • router.forward() : 소프트 네비게이션을 사용해 브라우저 히스토리 스택에서 다음 페이지로 이동

Navigation 작동 방식

  1. <Link> 나 router.push()를 사용해 라우트 전환을 시작.
  2. 라우터는 브라우저 주소 url 업데이트
  3. 라우터는 변경되지 않은 세그먼트(ex. 공유 레이아웃)를 클라이언트 캐시에서 재사용해 불필요한 작업을 피함.(= partial rendering)
  4. 소프트 네비게이션 조건을 충족할 경우, 라우터는 새 새그먼트를 서버에서 가져오는 대신 캐시에서 새 새그먼트를 가져옴! 그렇지 않으면 라우터는 하드 네비게이션을 수행, 서버에서 서버 컴포넌트 페이로드를 가져온다.
  5. 생성된 경우 로딩 UI가 페이로드를 가져오는 동안 서버에서 표시됨.
  6. 라우터는 캐시된 혹은 새로운 페이로드 사용해 클라이언트에서 새로운 세그먼트를 렌더링함.

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

새로운 라우터에는 서버 컴포넌트의 렌더링 결돠를 저장하는

인메모리 클라이언트 사이드 캐시가 있다.

이 캐시는 라우트 세그먼트별로 분할되어

어떤 수준에서도 무효화하고 동시 렌더링간 일관성을 보장한다.

 

사용자가 앱 내에서 이동할때, 라우터는 이전에 가져온

세그먼트의 페이로드 및 프리패치된 세그먼트를 캐시에 저장함.

 

이는 특정 경우에서 라우터가 캐시를 재사용해 새로운 요청을 서버에 보내지 않아도 됨.

이렇게 하면 데이터를 다시 가져오고, 컴포넌트의 불필요한 렌더링을 피한다.

이러한 것들이 성능을 향상하는 데 기여한다.

 

캐시 무효화

데이터를 필요할 때 경로별 혹은 캐시 태그별로

다시 유효성을 검사하기 위해 서버 액션을 사용할 수 있다.

 

Prefetching

해당 경로를 방문하기 전 백그라운드에서 라우트를 미리 로드하는 방법.

이에 대한 결과는 라우터의 클라이언트 사이드 캐시에 추가됨.

 

이렇게 하면 라우팅할때 거의 즉시 화면에 나타남.

 

기본적으로 뷰포트에 표시되는 순간에 <Link> 컴포넌트를 사용하여 라우트가 Prefectch됨.

이는 페이지가 처음로드되거나 스크롤할 때 발생할 수 있다.

또한 라우트는 useRouter() 훅의 prefetch 메서드를 사용하여 프로그래밍 방식으로 프리페치될 수 있다.

 

  • 라우트가 정적인 경우 : 라우트 세그먼트의 모든 서버 컴포넌트 페이로드가 Prefetch됨.
  • 라우트가 동적인 경우 : 첫 번째 공유 레이아웃부터 첫번째 loading.js 파일까지 페이로드가 Prefetch됨.
    이렇게 하면 동적 라우트 전체 Prefetch 비용감소하고, 동적 라우트에 대한 즉시로딩상태가 가능해진다.

소프트 네비게이션

Navigation 발생 시 변경된 세그먼트의 캐시를 재사용하고 데이터를 서버에 새로 요청하지 않는다.

* 캐시가 있다는 전제하에!

 

소프트 네비게이션의 조건

Next.js는 소프트 네비게이션을 사용해 아래 조건을 충족할 경우 수행함.

 

이동하려는 라우트가 프리페치되었고, 

동적 세그먼트를 포함하지 않거나 현재 라우트와 동일한 동적 매개변수를 가지고 있는 경우.

 

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

/blog/[slug]/*. 아래의 캐시된 세그먼트는 /blog/[slug]/*가 변경될 때만 무효화된다.

/dashboard/tslug-1/*에서 /dashboard/slug-1/*로 이동하는 경우 소프트 Navigation이 수행
/dashboard/slug-1/*에서 /dashboard/slug-2/*로 이동하는 경우 하드 Navigation이 수행.

 

하드 Navigation

Navigation 발생 시 캐시가 무효화, 서버가 데이터를 다시 가져오고 변경된 세그먼트를 다시 렌더링함.

 

뒤로/앞으로 Navigation

뒤로/앞으로 Navigation(popstate 이벤트)는 소프트 Navigation 동작을 수행한다.

이는 클라이언트 사이드 캐시가 재사용되고 Navigation이 거의 즉시 진행됨을 의미한다.