[Next.js] SEO와 "use client" 및 hydration

Yeong·2025년 3월 18일

현재 사내에서 next.js를 이용하여 개발 중인데, SEO가 중요하여 최대한 SSR로 작업하려하고있다.
최대한 "use client" 없이 사용하려하는데, 동적인 페이지가 많아 이에 대한 고찰이 필요하여 공부해본 내용을 적어본다.

🍀 use client

"use client";

import { useState } from "react";

next.js에서는 컴포넌트 상단에 위 코드와 같이 컴포넌트의 최상단에 "use client" directive를 추가할 수 있다.
해당 directive를 추가한 컴포넌트는 Client Component로 작동하게 된다.

하지만 next.js에서 컴포넌트가 client component로 작동한다고 해서 SSR이 아닌 CSR로 작동한다는 것은 아니다.

즉슨, 첫 렌더링은 서버에서 이루어진다!!
컴포넌트 최상단에 "use client"이 존재한다는 것은 해당 컴포넌트에 hydration이 일어난다는 의미이다.


여기에서 hydration의 개념을 알면 좋은데 그 전에 CSR과 SSR의 간단한 차이를 짚어보는게 좋을 것 같다.

🍀 CSR


CSR 방식의 경우 초기에 페이지를 로드할 때, 하나의 빈 html 파일과 거대한 js 번들 파일을 서버로부터 전달받게 된다.

React 프로젝트 내 사용되는 모듈(의존성, 컴포넌트 등등)들은 빌드 과정에서 하나의 거대한 js 파일로 번들링되기 때문에, 큰 용량으로 인해 초기 페이지 로딩에 있어 불리하다. (이 부분은 code splitting을 통해 해소가 가능하다)

또한 CSR 방식만을 채택하는 웹페이지는 하나의 html 파일만 존재해 SEO 최적화에 있어서도 불리하다.

🍀 SSR


CSR은 클라이언트(브라우저)에서 렌더링이 발생한다면, SSR은 호스트(서버)에서 렌더링이 발생한다. 이는 즉슨, 이미 서버에서 렌더링을 마쳤으므로 DOM 조작을 위한 추가적인 js 파일이 필요하지 않을 뿐더러, 컴포넌트 별로 완성된 html 파일로 제공되어 SEO 최적화에도 유리하다.

그렇다면 SSR 방식이 완성된 정적 html만을 제공한다면, 브라우저 상에서 발생하는 interactive한 event들은 어떻게 처리할까?

이를 해결하기 위한 방식이 바로 이번 글의 핵심인 hydration이다.

hydration은 우리가 받은 HTML 위에서 react application을 실행한다는 뜻이다.
(어떠한 HTML을 실제 interactive한 react 컴포넌트로 바꾸는 것)


🍀 Hydration

Hydration은 SSR로 제공된 컴포넌트에 interactive한 동작을 추가하기 위한 eventListener를 추가하는 과정이며, 이 과정을 하기위해 또 한번의 렌더링이 이루어진다.

사용자가 '/board'이라는 페이지로 접근한다고 할 때, next.js가 그 요청을 받으면 /app/board/page.tsx 컴포넌트를 html로 변환하여 응답으로 보내 사용자에게 보여준다.

이 때의 사용자에게 보여지는 html은 아무 인터렉션이 일어나지 않는 😇정적인 html 페이지이다.
(/board로 접근한 순간은 javascript도, 프레임워크도 로드되지 않은 단순 html파일이 보여지는 상태 )

동시에 next.js는 load를 시작해 react application을 초기화하여 정적인 html을 인터렉티브하게 만든다.

그 후 아주 빠르게 react가 initialize되면서 단순 HTML이 react component가 되는 것이다.

next.js 14에서 이 hydration은 모든 컴포넌트에서 일어나진 않는다.

😇 즉, hydration은 우리가 받은 HTML 위에서 react application을 실행한다는 뜻이다.
(어떠한 HTML을 실제 interactive한 react 컴포넌트로 바꾸는 것)


Next.js에서 기본적으로 모든 컴포넌트는 server side에서 pre render된다.

이 중 client에서 hydrate되는 컴포넌트,
즉 onClick, useState 등을 통해 client에서 인터렉티브하게 만들어질 컴포넌트는
"use client"를 가지고 있는 컴포넌트 뿐이다.
(의미적으로는 use client보다 use hydrate가 적합할 수 있다.)

Client Component vs Server Component

"use client" directive를 선언한 Client Component도 여전히 SSR로 동작하며 서버에서 Pre-Rendering이 이루어진다는 것이다. Client Component로 동작한다고 해서 CSR로 동작하는 것이 아니라는 점을 알아두자.

"use client"의 역할은 해당 컴포넌트에서 동적인 이벤트가 이루어질 수 있으며, 이벤트를 처리하기 위한 추가적인 js 파일과 hydration이 필요하다고 명시해두는 선언부로 생각해 볼 수 있다

☘️ client component
"use client" 를 선언하지 않은 컴포넌트는 server에서 render되고, client에서 hydrate된다.
☘️ server component
"use client" 를 선언하지 않은 컴포넌트는 server에서 render되고, hydrate되지 않는다.

즉 !! "use client"선언은 client에서만 render한다는게 아니라 client에서도 render된다는 뜻이다.


참고
https://limelbe.tistory.com/369
https://velog.io/@yeshyungseok/hydration%EA%B3%BC-use-client

0개의 댓글