2025.1.7 수요일의 공부기록
Next.js에서는 서버 컴포넌트(Server Components)와 클라이언트 컴포넌트(Client Components)를 구분해서 사용할 수 있다.
이 중 "use client"
는 특정 컴포넌트를 클라이언트 컴포넌트로 지정할 때 사용하는 지시문이다. 하지만 "use client"
를 추가한다고 해서 SSR(Server-Side Rendering)이 자동으로 비활성화되는 것은 아니다.
"use client"
란 무엇인가?Next.js 13부터 React의 서버 컴포넌트와 클라이언트 컴포넌트를 구분해서 사용하는 방식이 도입됐다.
기본적으로 Next.js는 모든 컴포넌트를 서버 컴포넌트로 처리하지만, 클라이언트 컴포넌트로 지정하려면 코드 상단에 "use client"
를 선언해야 한다.
useState
, useEffect
등)을 사용할 수 있다."use client"
와 SSR"use client"
를 추가한다고 해서 SSR이 완전히 비활성화되는 것은 아니다.
Next.js는 클라이언트 컴포넌트도 기본적으로 서버에서 초기 HTML을 렌더링한 후 브라우저에서 하이드레이션 과정을 거친다.
"use client";
import { useState } from "react";
export default function ClientComponent() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
"use client"
만으로는 SSR이 비활성화되지 않는다.
완전히 클라이언트에서만 렌더링하려면 아래 방법을 사용해야 한다.
dynamic
Import와 ssr: false
Next.js의 dynamic
을 사용해 컴포넌트를 동적으로 로드하면서, ssr: false
옵션을 설정하면 해당 컴포넌트는 클라이언트에서만 렌더링된다.
import dynamic from "next/dynamic";
const ClientOnlyComponent = dynamic(() => import("../components/ClientComponent"), {
ssr: false,
});
export default function Page() {
return (
<div>
<h1>Client Only</h1>
<ClientOnlyComponent />
</div>
);
}
ClientOnlyComponent
는 서버에서 렌더링되지 않는다.데이터 Fetching을 클라이언트 측에서 처리하도록 설정하면 해당 컴포넌트는 클라이언트 전용으로 동작한다.
"use client";
import { useState, useEffect } from "react";
export default function ClientOnly() {
const [data, setData] = useState(null);
useEffect(() => {
fetch("/api/data")
.then((res) => res.json())
.then((data) => setData(data));
}, []);
if (!data) return <p>Loading...</p>;
return <div>{JSON.stringify(data)}</div>;
}
"use client"
와 기본 렌더링 동작 비교항목 | 서버 컴포넌트(Server Component) | 클라이언트 컴포넌트(Client Component) |
---|---|---|
기본 렌더링 방식 | 서버에서 HTML 생성 (SSR) | 초기 렌더링은 서버에서 수행, 이후 브라우저에서 하이드레이션 |
React Hook 사용 여부 | 불가능 | 가능 |
브라우저 전용 API 사용 여부 | 불가능 | 가능 |
SSR 비활성화 방법 | 불가능 | dynamic 과 ssr: false 필요 |
하이드레이션(Hydration)은 서버사이드 렌더링(SSR)을 통해 생성된 정적인 HTML에 클라이언트 측의 React를 연결하여 인터랙티브한 React 컴포넌트로 변환하는 과정을 말한다.
서버에서 HTML 생성
Next.js와 같은 SSR 환경에서는 서버에서 초기 HTML을 생성하여 브라우저에 전달한다.
이 HTML은 정적이며, 아직 React의 상태 관리나 이벤트 핸들링 기능이 없다.
클라이언트에서 자바스크립트 로드
클라이언트는 자바스크립트를 로드하여 서버에서 생성된 HTML과 React의 상태 및 기능을 연결한다.
React의 상태 및 이벤트 연결
React는 하이드레이션 과정을 통해 HTML 구조에 상태 관리와 이벤트 처리를 추가하여 동작 가능한 인터랙티브 컴포넌트로 변환한다.
"서버 환경에서 이미 렌더링된 HTML에 React를 붙이는 과정"
즉, 정적 HTML을 클라이언트 측 자바스크립트를 통해 동적으로 만드는 것이다.
빠른 초기 로딩
SSR을 통해 생성된 HTML은 정적이기 때문에 브라우저가 빠르게 렌더링할 수 있다.
SEO 친화적
초기 HTML이 서버에서 생성되므로 검색 엔진 크롤러가 쉽게 접근할 수 있다.
React의 동적 기능 추가
클라이언트 측에서 React의 상태 관리와 이벤트 핸들링을 활성화하여 동적인 웹 페이지를 제공할 수 있다.
추가적인 자바스크립트 로드 필요
하이드레이션 과정에서는 클라이언트 측에서 추가적으로 자바스크립트를 로드해야 하므로 성능에 영향을 줄 수 있다.
복잡성 증가
서버에서 HTML을 생성하고, 클라이언트에서 이를 React로 연결하는 과정은 구현과 디버깅이 다소 복잡할 수 있다.
서버는 다음과 같은 정적 HTML을 생성하여 브라우저에 전달한다:
<div id="root">
<p>Count: 0</p>
<button>Increase</button>
</div>
React는 위 HTML을 기반으로 클라이언트 측에서 상태와 이벤트를 추가한다:
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
특징 | SSR + 하이드레이션 | CSR |
---|---|---|
초기 로딩 속도 | 빠름 (HTML 미리 생성됨) | 느림 (자바스크립트 로드 후 렌더링 시작) |
SEO 지원 | 우수 | 제한적 |
동적 기능 활성화 | 하이드레이션 과정에서 동작 시작 | 클라이언트 렌더링 완료 후 동작 |
복잡성 | 서버와 클라이언트의 협력 필요 | 클라이언트에서만 처리 (단순) |
필요한 부분만 하이드레이션
React의 클라이언트 컴포넌트와 서버 컴포넌트를 분리하여 필요한 컴포넌트만 클라이언트에서 하이드레이션하도록 설계한다.
지연 로드(Lazy Loading)
dynamic
import를 사용해 특정 컴포넌트를 동적으로 로드하여 초기 하이드레이션 부담을 줄인다.
경량 데이터 사용
서버에서 전달되는 HTML과 데이터를 최소화하여 하이드레이션 속도를 높인다.