JavaScript

Next.js에서의 Prefetching (<Link>컴포넌트와 Routing)

남희정 2023. 9. 6. 00:51

이전에 배운 preload, preconnect, prefetch로 리소스 우선순위를 변경하는 것을 배웠는데 next.js에서 이걸 어떻게 차용했고 어떤 효과를 이루어 냈는지를 알아볼 것이다. 우선 next.js에 대해서 먼저 알아보자.


Next.js 란?

The React Framework for the Web 

빠른 웹 애플리케이션을 만들 수 있는 빌딩 블록을 제공하는 유연한 React 프레임워크이다. React 구성요소를 사용하여 UI를 구축하고 Next.js를 사용하여 추가 기능과 최적화를 수행한다. 내부적으로 Next.js는 번들링, 컴파일 등과 같이 React에 필요한 도구를 추상화하고 자동으로 구성하여 구성에 시간을 낭비하는 대신 애플리케이션 구축에 집중할 수 있게 해준다.

 

 

주요 특징

Next.js의 주요 기능

특징 설명
Routing 서버 컴포넌트 위에 구축된 파일 시스템 기반 라우터로 레이아우스 중첩된 라우팅, 로딩 상태, 오류 처리 및 기타 기능을 지원한다.
Rendering Next.js를 통한 클라이언트 측 및 서버 측 렌더링과 클라이언트 및 서버 컴포넌트로 진행된다. Next.js에서 서버에서 정적 및 동적 렌더링을 더 최적화하며, Edge 및 Node.js 런타임에서 스트리밍을 지원한다.
Data fetching 서버 컴포넌트에서 async/await 기능을 통해 데이터 fetching을 간소화하고, 요청 memoization, 데이터 캐싱 및 재검증을 위한 확장된 fetch API를 제공한다.
Styling CSS module, Tailwind CSS, CSS-in-JS 등 선호하는 스타일링 방법 지원
Optimizations 이미지, 글꼴 및 스크립트 최적화를 통해 애플리케이션의 Core Web Vital과 UX를 개선한다
TypeScript 타입 검사 및 컴파일 효율성이 개선되고 사용자 지정 타입스크립트 플러그인 및 타입 검사기를 통해 타입스크립트에 대한 지원이 향상되었다

 

이 중에서 오늘 들여다 볼 것은 Routing이다. 모든 애플리케이션의 골격은 라우팅이다.

 

Route Segments

Next.js에서는 File System Based Routing을 한다.기존의 React Router에서는 꽤 상위 컴포넌트에서 <Route path='/' element={<Main />} /> 이런 식으로 원하는 경로마다 설정해줘야 했다. 하지만 Next.js는 pages 폴더 내의 파일 구성에 따라 Routing이 만들어진다.

 

Routing 기본 용어

 

라우팅 기본 용어

트리(Tree)

계층 구조를 시각화하는 데 사용되는 규칙 또는 방법. 예를 들어, 부모 및 자식 컴포넌트로 구성된 컴포넌트 트리, 폴더 구조 등

서브트리(Subtree)

새로운 루트(첫 번째 노드)에서 시작하고 말단(마지막) 노드에서 끝나는 트리의 일부분.

루트(Root)

트리 또는 서브트리에서의 첫 번째 노드로, 루트 레이아웃과 같은 것.

말단(Leaf)

서브트리 내에서 자식이 없는 노드로, URL 경로의 마지막 세그먼트와 같은 것.

 

URL 구조

URL 세그먼트(URL Segment)

슬래시로 구분된 URL 경로의 일부분

URL 경로(URL Path)

도메인 이후에 나오는 URL의 일부로, 세그먼트로 구성됨.

 

어떤 컨텐츠를 어떤 방식으로 보여줄 것인가? Routing으로 페이지 사이의 관계를 만들었다면 그 사이에서 어떻게 움직일지도 중요하다.

APP Router와 Page Router

Next.js에는 앱 라우터와 페이지 라우터라는 두 가지 라우터가 있다.

app 디렉토리, pages 디렉토리

Page Router

페이지 라우터는 서버 렌더링된 React 애플리케이션을 빌드할 수 있게 해준 오리지널 Next.js 라우터로, 이전 Next.js 애플리케이션에 대해 계속 지원된다. Next.js 13이전.

APP Router로 마이그레이션하는 것을 권장한다.

 

APP Router

버전 13에서 공유 레이아웃, 중첩 라우팅, 로딩 상태, 오류 처리 등을 지원하는 React 서버 컴포넌트에 기반한 새로운 앱 라우터가 도입되었다.

앱 라우터는 app이라는 새 디렉토리에서 작동한다. 앱 디렉토리는 페이지 디렉터리와 함께 작동하여 점진적인 적용이 가능하기 떄문에 앱 일부 경로를 새 동작으로 선택하고, 다른 경로는 이전 동작을 위해 페이지 디렉토리에 유지할 수 있다. 

 

✔️ Page Router보다 우선된다. 디렉토리를 가로지르는 경로는 동일한 URL 경로가 되지 않아야하고 충돌을 방지하기 위해 빌드 시간 오류가 발생할 수 있음.

정확한 사용방법은 추후에.. Next.js를 사용할 때 들여다 보자.

 

Linking and Navigating 

Next.js에서 경로 간 탐색을 하는 방법에는 두 가지가 있다.

 

1️⃣ <Link> 컴포넌트 사용하기

2️⃣ useRouter Hook 사용하기

 

훅(Hooks)? React에서 use로 시작하는 함수들을 훅이라고 한다. 

 

<Link> Component

<Link>는 HTML <a> 태그를 확장하여 경로 간 prefetching 및 클라이언트 측 탐색을 제공하는 기본 제공 컴포넌트이다.

`next/link`에서 컴포넌트를 가져와서 컴포넌트에 href 프로퍼티를 전달하면 사용할 수 있다. 

 

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

 

prefetch

true가 Default. true로 설정하면 next/link는 페이지(링크의 href로 표시됨)를 백그라운드에서 프리페치(prefetch)한다.

클라이언트 측 네비게이션의 성능을 향상시키는 데에 유용하다. 뷰포트 안에 있는(초기에 또는 스크롤을 통해 나타나는) 모든 <Link />는 preload된다. prefetch를 비활성화하려면 prefetch={false}를 전달할 수 있다. 

 

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

a태그에 마우스 hover시 네트워크에서 preload로 fetching하는 것을 확인할 수 있다.

 

useRouter() Hook

useRouter() hook을 사용하면 프로그래밍 방식으로 경로를 변경할 수 있다. 이 Hook은 클라이언트 컴포넌트 내에서만 사용할 수 있으며 next/navigation 에서 가져온다.

 

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

 

How Routing and Navigation Works ?

동작방식?

앱 라우터는 라우팅 및 네비게이션을 위해 하이브리드 접근 방식을 이용한다.

서버에서는 애플리케이션 코드를 Route Segments별로 자동으로 코드 분할한다. 그리고 클라이언트에서는 Next.js가 Route Segments를 preload하고 캐싱한다. 이건 새로운 경로로 이동할 때 브라우저가 페이지를 다시 로드하지 않고 변경된 Route Segment만 다시 렌더링하여 네비게이션 경험과 성능을 개선한다.

 

1. Prefetching

prefetching은 사용자가 방문하기 전에 백그라운드에서 Route를 preload하는 방법이다.

위에서 보았듯, Route가 prefetch되는 방식은 두가지가 있다.

 

1️⃣ <Link> 컴포넌트 

Route는 사용자의 Viewport에 표시될 때 자동으로 prefetch된다. 페이지가 처음 로드될 때 또는 스크롤을 통해 보이게 될 때 발생한다. 

2️⃣ router.prefetch()

useRouter 훅을 사용하여 Route를 프로그래밍 방식으로 prefetch할 수 있다.

 

<Link>의 prefetching 동작은 정적, 동적 라우트에 따라 다르다.

 

✔️ Static Routes 정적 라우트

prefetch는 기본값으로 true로 설정된다.

전체 라우트가 prefetch되고 캐싱된다.

 

✔️ Dynamic Routes 동적 라우트

prefetch는 기본값으로 automatic으로 설정된다.

첫 번째 loading.js 파일까지의 공유 레이아웃만 prefetch되고 30초동안 캐시된다.

➡️ 전체 동적 라우트를 가져오는 비용이 감소하며 사용자에게 빠른 시각적 피드백을 위한 instant loading state를 표시할 수 있다.

비활성화시 false로 설정할 수 있다.

 

✶ 프로덕션 환경(사용자에게 실제로 제공되고 운영되는 환경)에서만 활성화된다. 

 

2. Caching

Next.js에는 라우터 캐시(Router Cache)라고 하는 in-memory client-side cache가 있다. 사용자가 앱을 탐색하는 동안 prefetch된 Route segment와 방문한 Route의 React Server Component Payload가 캐시에 저장된다.
탐색 중에는 새로운 요청을 하는 대신 최대한 캐시를 재사용하여 요청 및 데이터 전송 횟수를 줄여 성능을 개선한다.

 

*Server Component Payload?

서버 측에서 클라이언트에게 전송되는 데이터 및 상태를 나타낸다. 서버 컴포넌트가 서버에서 클라이언트로 렌더링되는 과정에서 전달되는 정보를 포함한다. 

 

3. Partial Rendering

부분 렌더링은 네비게이션에서 변경된 Route Segment만 클라이언트에서 다시 렌더링하고 공유 Segments는 모두 보존하는 것을 의미한다.

 

Rendered on Navigation

 

부분 렌더링이 없으면 탐색할 때마다 전체 페이지가 서버에서 다시 렌더링 된다. 변경되는 Segment만 Rendering하면 전송되는 데이터의 양과 실행 시간이 줄어들어 성능이 향상된다. 

 

4. Soft Navigation

기본적으로 브라우저는 페이지간 Hard navigation을 수행한다. 즉, 브라우저는 페이지를 다시 로드하고 앱의 useState() Hooks 같은 React 상태와 사용자의 스크롤 위치 또는 포커싱된 요소와 같은 브라우저 상태를 재설정한다. 하지만 Next.js에서 앱 라우터는 Soft Navigation을 사용한다. 즉, React는 React와 브라우저 상태를 유지하면서 변경된 Segment만 렌더링하며 전체 페이지를 다시 로드하지 않는다.

 

Hard navigation이란? 명시적인 명령 또는 규칙에 따라 시스템이 환경을 탐색하고 이동하는 방식. 주로 미리 정의된 경로, 방향 또는 동작을 사용하여 탐색하는 것을 의미한다.

 

5. Back and Forward Navigation

기본적으로 Next.js는 뒤로 가기/앞으로 가기를 위한 스크롤 위치를 유지하고 Router Cache에서 Route Segment를 재사용한다.

 

 

🤔 💭

아는 만큼 보인다고, Next.js를 써보지 않는 이상 완전히 이해는 불가능할 것 같다. 아쉬운 점이다. js script 비동기부터, prefetch, preload, preconnect에서 Next.js 라우팅, 파일 시스템 기반으로 경로 설정하는 것에서 캐싱.. 등등 엮어나갈 수 있는 부분이 굉장히 많았고 SPA, CSR, SSR.. 더 담아낼 수 있는 것들이 많았으나 포스트 1개로는 역부족이고 실제로 써보지도 못한 사람으로써 떳떳하진 못했다. 정리한다고 해서 내 것으로 만들 수 없는 영역이라고 해야하나. 그래도 최신 기술 스택이 성능 개선을 위해 어떤 것까지 신경쓰는지 알 수 있는 시간이었다. 불필요한 공부는 없다는 걸 나는 잘 안다. 이해할 날을 기다려보아야겠다.


<Link>

Linking and Navigating

[Next JS] Pages Router 에서 App Router 전환기

03) Next.js 페이지와 라우팅

[nextjs] 13.4.0부터 안정화된 App Router. Pages Router와 비교

useRouter

Web: Next.js Link와 Prefetch 과정 파헤쳐보기