Programming/Next.js

[Next.js 13] Next.js 13버전의 서버 중심 라우팅과 클라이언트 사이드 네비게이션 정리

리버김 2023. 2. 5.
이번 주에 공식문서 Page and Layouts 까지 읽었고, 이번엔 Next.js의 Linking and Lavigating에 대해 배워 보자. 따로 링크되지 않은 모든 설명은 Next.js 공식문서가 출처다.
 

Routing: Fundamentals | Next.js

...

beta.nextjs.org

서론: Next.js 13은 서버가 라우팅하고 클라이언트가 네비게이트한다.

pages 디렉토리와는 달리, app 디렉토리의 new! 라우터는 서버 중심 라우팅을 사용한다. 이는 Server Component와 서버에서의 data fetching와 궤를 같이 하는 것이다. 클라이언트는 router 지도를 다운 받을 필요가 없다 .

 

(app directory의 모든 컴포넌트들은 디폴트로 RSC(React Server Components)다. 클라이언트 컴포넌트는 파일 첫줄에 'use client'라고  입력하면 된다. 공식문서에서 각각 쓸 수 있는  경우를 잘 정리하고 있다. 예를 들어 클라이언트 컴포넌트에 검색 결과를 fetching하여 state에 저장하는 코드를 작성하고, 그것을 서버 컴포넌트에 interleave(끼워 넣다)하여 nested layout으로다가 필요한 부분만 재랜더링 하면 된다. 반면 서버 컴포넌트에서 useState 쓰면 에러를 뿜는다. 신박하다! RSC에 대해서도 좀 더 깊이 있게 정리해보자.)

https://programming119.tistory.com/252

 

[React🌀] React 서버 컴포넌트 / RSC의 도입 배경과 장점

들어가며 프론트엔드 세계에는, 시간이 갈수록 정말 많은 변화를 겪고, 많은 유용한 프레임워크와 라이브러리들이 생겨나고 있습니다. 그 중에 중요한 요소중 하나가 data를 fetching 및 rendering하

programming119.tistory.com

 

라우팅은 서버 중심적이나, 네비게이션은 Link 컴포넌트를 사용하여 클라이언트 사이드 네비게이션을 사용한다. 이는 SPA와 닮은 것이다. 사용자가 새로운 route로 navigate할 때, 브라우저가 페이지를 새로고침하는 대신, Next.js가 바뀐 요소만 재렌더링 한다.(예를 들어 한 layout 하의 형제 페이지들 사이를 이동한다면 변경된 부분부분들만 렌더링해주는 것이다.)

 

또 사용자가 navigate할 때 RSC가 그 결과들을 클라이언트 사이드의 인메모리 캐시(Redis가 생각난다!)에 저장한다. 그러니까 어떤 경우에는 캐시를 사용하여 성능을 더욱 향상시킬 수 있다.

 

본론: Linking and Routing

Next.js 라우터는 서버 중심 라우팅과 클라이언트 사이드 네비게이션을 사용한다. instant loading states와 동시 렌더링을 지원한다. 이는 네비게이션이 클라이언트 사이드의 상태를 유지하며, 값비싼 리렌더링을 피한다는 것을 의미한다. 본격적으로 Linking과 Routing에 대해 자세히 알아보자.

 

navigate하는 두 가지 방법이 있다.

  1. <Link> 컴포넌트
  2. useRouter 훅

 

<Link> 컴포넌트

<Link>는 HTML <a>  요소를 확장한 React 컴포넌트다. prefetching과 클라이언트 사이드 네비게이션을 지원한다. Next.js에서 사용되는 주요한 네비게이션 방법이다. template literal을 사용해 동적 linking도 물론 가능하다.

 

*Prefetching이라는 새로운 개념이 나와 찾아보니 route가 방문되기 전에 preload하는 것이다. 그 결과물은 클라이언트 사이드의 캐시에 저장되고, 더 빠르게 네비게이트 해준다. Link 컴포넌트가 브라우저 상에 띄워질 때마다 background에서 Link된 페이지의 코드를 미리 가져와 놓고는, 이를 통해 SPA와 비슷하게 빠른 페이지 전환 효과를 제공하는 거다. 

 

 

예시

// app/page.tsx

import Link from 'next/link';

export default function Page() {
  return <Link href="/dashboard">Dashboard</Link>;
}

 

useRouter() Hook

useRouter hook은 클라이언트 컴포넌트 내부에서 route를 옮길 수 있게 해준다. 사용하려면 next/navigation을 import해야 한다. push(), refresh()와 같은 함수들을 제공하며, 관련 API 문서에서 확인할 수 있다.

 

예시

'use client';

import { useRouter } from 'next/navigation';

export default function Page() {
  const router = useRouter();

  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  );
}

 

Navigation은 이렇게 이루어진다.

  • route 전환은 <Link>나 router.push() 함수 호출로 이루어진다.
  • router는 브라우저 주소 바에 URL을 업데이트 한다.
  • router은 클라이언트 사이드 캐시에 저장해뒀던 요소들을 재활용하여 불필요한 일을 피한다.
  • 만약 soft navigation의 조건이 충족된다면 router는 서버가 아닌 캐시에서 새로운 요소를 불러온다. 아니라면 router는 hard navigation을 수행하여 Server Component를 서버로부터 받아 온다.
  • 서버로부터 컴포넌트가 받아져 오는 동안 loading UI가 서버로부터 보여진다.
  • router는 클라이언트에 새로운 요소를 렌더하기 위하여 캐시되었거나 fresh한 페이로드를 사용한다.

 

캐시 무효화

캐시는 router.refresh() 호출 시 무효화된다. 나중에 배울 mutations는 자동적으로 캐시를 무효화 할 것이다. 인메모리 캐싱에 대해서는 위에 언급했다.

 

Hard Navigation

네비게이션에서, 캐시가 무효화되고 서버는 데이터를 refetch하며 변경된 구획들을 re-render하는 것이다.

Soft Navigation

네비게이션에서, 변경된 구획에 대한 캐시가 있다면 재사용되며, 서버에 새로운 데이터 요청이 가지 않는 것이다.

Soft Navigation의 조건은?

네비게이션에서 만약 내가 가려는 route가 prefetch 되었으며 동적 구획 혹은 현재 route와 같은 동적 파라미터를 가지지 않았다면 soft navi를 사용할 거다.

 

예를 들면 /dashboard/[team]과 같이 동적 구획을 가진 route가 있다면, 캐시는 team이 변경될 때만 무효화될 거다.

 

뒤로가기/앞으로 가기

soft navi와 같은 메커니즘을 쓴다. 즉 클라이언트 사이드 캐시가 재사용된다는 거다.

 

반응형

댓글