Next.js는 리액트를 기반으로 한 자바스크립트 프레임워크로, 풀스택 웹 어플리케이션을 구축하기 위해 사용된다. 리액트 컴포넌트로 UI를 만들고, Next.js 사용해서 추가 기능과 최적화를 수행한다.
리액트는 공식문서에서 라이브러리라고 소개하고 있는데 넥스트는 프레임워크라고 표현했다. 넥스트는 리액트를 기반으로 해서 만들어진 것인데, 왜 리액트는 라이브러리라고 하고 넥스트는 프레임워크라고 할까? 이에 대해 설명을 해놓은 공식 홈페이지 글을 찾을 수 있었다. (링크 : About React and Next.js)
여기서 Next.js는 풀 스택 웹 어플리케이션을 빠르게 만들 수 있는 'building blocks'를 제공한다고 써있다. 웹 어플리케이션을 만들기 위해서는 UI, 라우팅, 데이터 fetching, 렌더링 등등의 요소가 필요하다. 리액트는 UI라는 하나의 요소를 만들기 위해 사용하는 라이브러리이다. 하지만 넥스트는 UI뿐만 아니라 렌더링, 라우팅 등 다양한 요소들을 프로젝트에 쉽게 적용할 수 있도록 기능을 제공해준다. 대신 라이브러리를 쓸 때와는 달리 그 기능을 위해 어떤 프로그램을 쓸 지는 사용자가 마음대로 정할 수 없다. 넥스트에서 UI를 만드려면 반드시 리액트 컴포넌트를 사용해야하는 것과 같다. 따라서 넥스트는 프레임워크라고 할 수 있다.
SSR을 지원한다는 사실은 넥스트의 가장 큰 특징이자 장점으로 꼽힌다. SSR은 서버에서 미리 페이지를 렌더링 해서 보내주기 때문에, CSR에 비해 초기 로딩 속도가 빠르고 검색 엔진 최적화가 가능하다.
하지만 넥스트는 모든 컴포넌트를 SSR로 처리하진 않는다. 넥스트는 기본적으로 모든 페이지를 pre-rendering한다. 서버에서 미리 HTML 페이지를 생성한다는 말이다. Pre-rendering에는 두가지 방법이 있다. 정적 사이트 생성(SSG)(+ISR)과 서버 사이드 렌더링(SSR)이다.
정적 사이트 생성 (Static Site Generation)
HTML을 빌드 시점에 생성한다. 이렇게 생성된 HTML은 매 요청마다 재사용된다.
증분 정적 재생성 (Incremental Static Regeneration)
SSG와 마찬가지로 빌드 시점에 HTML을 생성하지만, 일정 주기마다 페이지를 다시 생성해준다. SSG는 데이터가 업데이트 되면 페이지를 새로 빌드해야 하지만, ISR은 빌드를 다시 하지 않아도 된다.
서버 사이드 렌더링 (Server Side Rendering)
요청이 들어오면 HTML을 생성한다.
넥스트는 Static Rendering(기본값)과 Dynamic Rendering 방식이 있다. SSG를 위해서는 어떤 렌더링 방식을 사용할지, SSR을 위해서는 어떤 렌더링 방식을 사용할지 고민할 필요 없이 fetch() 함수의 옵션을 원하는 대로 설정해주면 자동으로 렌더링 방식을 정해준다.
SSG
const response = await fetch("https://...", {cache: "force-cache"});
// 또는 생략 가능
const response = await fetch("https://...");
cache 옵션을 force-cache로 주면 SSG 방식을 사용한다. 빌드 시점에 데이터 페칭을 진행하고, 직접 무효화하기 전까지 데이터를 캐싱한다. 기본값이어서 생략 가능하다.
SSR
const response = await fetch("https://...", {cache: "no-store"});
cache 옵션을 no-store로 주면 SSR 방식으로 작동한다. 불러온 데이터를 캐싱하지 않고 요청이 들어올 때마다 데이터를 패칭하여 페이지를 만들어준다.
ISR
const response = await fetch("https://url", {next: {revalidate: 60});
next 옵션에서 revalidate값을 설정한다(초 단위). cache 옵션의 force-cache값이 기본으로 적용되어 빌드시에 페이지를 생성하지만, revalidate의 값으로 준 시간이 지나면 페이지를 새로 생성한다.
서버 컴포넌트는 서버에서만 동작하는 컴포넌트를 말한다. React 18, Next 13부터 도입된 개념으로, 이 이전 버전의 리액트는 클라이언트 컴포넌트만 사용했다. 지금도 리액트는 기본적으로 클라이언트 컴포넌트를 사용하지만, 넥스트는 특별한 설정을 하지 않을 경우 서버 컴포넌트를 사용한다.
서버 컴포넌트는 SSR과 같지 않다. 서버 컴포넌트는 SSR을 대체하기 위한 기능이 아니라, 상호 협력적인 관계라고 생각하면 된다. 초기 HTML을 생성하기 위해서는 SSR이 필요하고, 서버 컴포넌트는 특정 컴포넌트가 클라이언트로 전달되지 않고 서버에서만 실행되도록 사용할 수 있다.
SSR은 HTML로 전달되기 때문에 refetch가 필요한 경우 HTML 전체를 다시 리렌더링 해야한다. 하지만 서버 컴포넌트는 HTML이 아니라 네트워크로 전송하기 더 적합한 JSON 유사 표기법의 형태로 클라이언트에게 전달된다. 따라서 서버 컴포넌트를 사용하면 페이지 전체를 다시 받아올 필요 없이 필요한 데이터만 리렌더링해서 클라이언트로 전달해줄 수 있다.
더 자세한 설명은 여기 ⬇️
서버 컴포넌트에도 분명한 한계가 있다. 서버에서 렌더링 되기 때문에 이벤트 핸들러, useEffect, useState 등의 기능을 사용할 수 없고, 유저와의 상호작용이 어렵다는 점이다. 그렇지만 넥스트에서도 클라이언트 컴포넌트를 통해 이러한 한계를 극복할 수 있다.
클라이언트 컴포넌트를 사용하려면 컴포넌트 파일 최상단에 "use client"를 추가하면 된다. 그러면 리액트에서 했던것과 마찬가지로 리액트 훅과 이벤트 핸들러 등을 사용할 수 있게 된다.
다만, 클라이언트 컴포넌트는 클라이언트 컴포넌트만 import 할 수 있다는 것을 알아두어야 한다. 어떤 컴포넌트를 클라이언트 컴포넌트로 선언했다면, 그 컴포넌트의 자식들은 "use client"를 적어주지 않아도 전부 클라이언트 컴포넌트가 된다. 클라이언트 컴포넌트가 리렌더링이 되면 그 아래의 자식 컴포넌트들도 리렌더링이 되어야 하는데, 서버 컴포넌트는 하이드레이트 되거나 다시 렌더링을 할 수 없어 부모 컴포넌트가 바뀌어도 리렌더링이 불가능하기 때문이다.
넥스트에서 클라이언트 컴포넌트를 사용한다고 해서 전통적인 클라이언트 사이드 렌더링(CSR) 방식을 사용하는 것은 아니다. 서버에서 렌더링한 HTML과 번들링 된 JS 파일을 클라이언트로 보내면, 클라이언트 측에서는 이 HTML을 JS 코드와 연결하는 작업을 한다. 클라이언트가 HTML과 JS 코드를 연결해주는 이 과정을 하이드레이션이라고 부른다. 사용자는 서버에서 pre-rendering 된 페이지를 빠르게 볼 수 있고, hydration이 끝나면 상호작용이 가능해진다.

이 과정에서 이전 단계가 끝나기 전에는 다음 단계가 진행될 수 없다. 따라서 사용자가 페이지 또는 원하는 정보를 늦게 받아보게 되거나, 상호작용을 할때까지 오래 기다리게 되는 현상이 생길 수 있다. 이 문제는 Suspense를 사용하여 해결할 수 있다.
import { Suspense } from 'react'
import { PostFeed, Weather } from './Components'
export default function Posts() {
return (
<section>
<Suspense fallback={<p>Loading feed...</p>}>
<PostFeed />
</Suspense>
<Suspense fallback={<p>Loading weather...</p>}>
<Weather />
</Suspense>
</section>
)
}
데이터를 불러와야 하는 컴포넌트를 <Suspense>로 감싸면, 해당 컴포넌트의 데이터가 불러와지는 동안 다른 부분은 이를 기다리지 않고 스트리밍 기능을 통해 먼저 화면에 그려지고 하이드레이션이 진행될 수 있다. 데이터 패칭이 진행되는 동안에는 fallback에 지정해준 컴포넌트가 그려진다. 데이터 패칭이 끝나면 그 컴포넌트는 fallback 컴포넌트 자리에 들어가게 된다.
그리고 여러개의 컴포넌트가 하이드레이션이 진행되지 않은 상황에서 사용자가 한 컴포넌트를 클릭할 경우, 리액트는 해당 클릭을 기록해두었다가 사용자가 클릭한 컴포넌트에 대한 하이드레이션에 우선순위를 부여한다. 이렇게 화면 상에서 급한 부분을 먼저 하이드레이션 하는 것도 가능하게 해준다.
참고자료