지난 글에서 웹 애플리케이션의 페이지 구성 방식인 SPA, MPA와 이를 구현하는 렌더링 방식인 CSR, SSR에 대해서 알아보았다. 이번 글에서는 이러한 렌더링 방식을 Next.js에서 어떻게 구현하고 있는지, 이러한 렌더링 방식을 선택해서 사용하기 위해서는 어떤 작업을 해줘야 하는 지 자세히 알아보자.
일반적인 React
를 사용한 웹 어플리케이션은 CSR 렌더링 방식을 사용하며, 이는 처음에 브라우저가 빈 HTML 파일을 받아 아무것도 보여주지 않다가, JavaScript가 다운로드 완료되 사용자의 기기에서 렌더링이 진행되어 한 번에 화면을 보여준다.
하지만 Next.js
는 모든 페이지를 사용자에게 전해지기 전에 미리 렌더링 즉, Pre-Render 한다. 이는 Next.js가 모든 일을 클라이언트 측에서 모든 작업을 수행하는 것이 아니라, 각 페이지의 HTML을 미리 생성하는 것이다.
생성된 HTML은 해당 페이지에 필요한 최소한의 자바스크립트 코드와 연결된다. 그후 브라우저에 의해 페이지가 로드되면, 자바스크립트 코드가 실행되어 페이지와 유저가 상호작용할 수 있게 된다.
이러한 과정을 Hydration이라 한다.
<Link>
같은 컴포넌트는 동작하지 않는다.하지만 일반적인 React 어플리케이션처럼 Pre-Rendering이 없다면 js 전체가 로드되어야 하기 때문에 최초 load에서 사용자에게 보여지지 않게 된다. 즉, 전체 페이지가 로드되기 전 사용자는 페이지를 볼 수 없다.
Next.js에서의 Pre-Rendering은 2가지 종류가 있다.
1) Static Generation (정적 생성)
2) Server-side Rendering (서버사이드 렌더링)
⇒ 둘의 차이는 웹 페이지를 위한 HTML을 언제 생성하느냐에 있다.
빌드 타임에 HTML을 생성하는 프리 렌더링 방법이다. 이렇게 프리 렌더링 된 HTML은 매 요청마다 재사용된다. next build 명령을 통해 웹 앱을 프로덕션 레벨로 빌드했을 경우, 이 시점에 HTML이 렌더링 되고, 각각의 클라이언트들이 요청할 때마다 이미 만들어진 해당 HTML이 재사용된다.
즉, Next.js에서의 SSG도 결국 서버에서 렌더링되므로 서버사이드 렌더링으로 볼 수 있다. 하지만 Next.js 안에서 렌더링된 파일을 생성하는 시점에 따라 렌더링 방식을 구분하기 위해 SSG와 SSR로 나눠서 부르는 것 같다.
매 요청마다 HTML을 생성하는 프리 렌더링 방법이다. 그저 각각의 클라이언트들이 요청을 하는 시점에 매번 HTML을 생성한다. npm run dev 나 yarn dev를 통해 실행된 개발 환경에서는, 페이지들이 Static Generation을 사용하고 있더라도 모든 페이지들이 매 요청마다 프리렌더링 된다.
next.js에서는 다음과 같이 총 4가지의 렌더링 방식을 제공한다.
Page Router에서의 렌더링 방식
Next.js 13 이전의 Page Router 방식에서는 다음 렌더링 방식들을 다음과 같은 방법으로 구현했다.
- CSR :
useEffect
사용- SSR :
getServerSideProps
api 사용- SSG :
getStaticProps
api 사용- ISR :
getStaticProps
+revalidate
api 사용Page Router 방식은 현재 별로 권장되지는 않는 방식이기 때문에 이 정도로만 간략하게 설명하고 넘어가겠다. 더 자세한 설명은 여기를 참고하면 좋을 것 같다.
App Router에서도 동일하게 SSR, SSG, CSR, ISR 총 4개의 렌더링 방식을 지원한다. 이를 각각 어떻게 사용할 수 있는지 알아보자.
fetch('https://...', { cache: 'no-store' }
옵션을 통해 이를 구현할 수 있다.data 요청 중일 때, 브라우저는 loading-state가 될 것이다.
jsx/tsx
파일 상단에 'use client;'
를 적어줌으로써 구현할 수 있다.fetch
함수를 사용하면 구현이 가능하다.
fetch
함수의 기본적인 옵션 값이cache: force-cache
이기 때문에 아무런 옵션을 주지 않는다면 SSG 방식으로 동작한다.
fetch('https://...', { next: { revalidate: 10} })
옵션을 줌으로써 구현이 가능하다.각 렌더링 방식을 살펴보면,
각 렌더링 방식을 어떻게 사용할 수 있는지만 정리해보면, 다음과 같이 요약할 수 잇다.
fetch
사용fetch('https://...', { next: { revalidate: 10} })
fetch('https://...', { cache: 'no-store' }
jsx/tsx
파일 상단에 'use client;'
Next.js에서는 다양한 렌더링 방식을 지원하는 것을 살펴보았는데, 그러면 언제 어떠한 렌더링 방식을 선택하는 것이 좋을까 ??
가능하면 SSG 렌더링 방식을 사용하는 것이 좋다고 한다.
⇒ 페이지가 한번에 빌드되고 CDN에 의해 서비스되는 것이 매 요청마다 서버가 페이지를 렌더링하게 만드는 것보다 훨씬 빠르기 때문이다.
Ex) Static Generation은 다음 예시들을 포함한 많은 상황들에서 사용할 수 있다.
=> 마케팅 페이지, 블로그 포스트, 이커머스 (쇼핑몰) 제품 목록, 도움이나 기록을 위한 페이지 등.
⇒ 따라서, 유저의 요청 이전에 페이지를 렌더링할 수 있는 상황이면, SSG를 사용하는 게 좋다.
유저의 요청 이전에 페이지를 렌더링 할 수 있는 상황
하지만 만약 유저의 요청 이전에 페이지를 프리렌더링 할 수 없다면, SSG는 좋은 방법이 아니다.
⇒ 유저의 요청 전에 data를 불러오면 안되는 경우, 유저의 요청에 따라 불러올 data가 바뀌는 경우
=> 해당 페이지가 자주 업데이트되는 페이지를 보여주거나 매 요청마다 페이지의 컨텐츠가 바뀐다면 이런 경우는 SSR을 사용해야 한다.(프리 렌더링 된 페이지가 항상 최신 상태로 유지될 수 있음)
=> 아니면 자주 업데이트되는 데이터를 관리하기 위해 CSR을 사용할 수도 있다.
[Next.js] Pre-Rendering
Understanding Next.js Rendering Strategies — SSR, CSR, SSG & ISR
Nextjs data Fetching 이해하기 (CSR, SSR, SSG, ISR)