React Hydration - 서버에서 클라이언트로 이어지는 렌더링의 흐름

SilverAsh·2025년 10월 29일
0

React

목록 보기
2/5

React로 서버사이드 렌더링(SSR)을 하다 보면 Hydration, Streaming SSR, Flight 같은 단어들이 등장한다.
이 글에서는 React가 SSR 이후 어떻게 브라우저에서 살아나는지, 그리고 그 내부 구조가 어떻게 발전하고 있는지를 단계별로 정리해 보겠다.


SSR 이후,

서버사이드 렌더링(SSR)은 React를 실행시켜 HTML을 만들어 서버에서 먼저 보낸다는 뜻이다.
사용자는 자바스크립트가 로드되기 전에도 완성된 화면을 볼 수 있다.

하지만 이 HTML은 단순한 정적 마크업일 뿐,
버튼을 눌러도 동작하지 않고 useState, useEffect 같은 훅도 실행되지 않는다.

그래서 필요한 과정이 바로 Hydration(하이드레이션) 이다.


Hydration이란

Hydration은 클라이언트가 서버로부터 받은 HTML을 다시 React 앱으로 되살리는 과정이다.

즉,

  • HTML 구조는 그대로 유지한 채,
  • React의 가상 DOM(Fiber Tree)을 새로 만들고,
  • 기존 DOM 노드와 연결(binding)하여
  • 이벤트 핸들러, 상태, 컴포넌트 트리를 다시 활성화한다.
// 서버가 보낸 HTML
<div id="root"><button>좋아요</button></div>

// 클라이언트에서 실행
hydrateRoot(document.getElementById('root'), <App />);

이 시점에서 React는
기존 DOM과 새로 렌더링된 가상 DOM이 동일한가?를 비교하며 reconciliation(재조정)을 수행한다.
만약 서버에서 렌더된 결과와 클라이언트 렌더 결과가 다르면
React는 경고를 띄우거나 DOM을 재생성한다.


Fiber Tree 복원의 내부 구조

React는 16 버전 이후부터 Fiber 구조를 사용해 렌더링을 관리한다.
Hydration 시점에는 기존 DOM 트리를 기반으로 새로운 Fiber Tree를 구성하지만,
HTML을 다시 그리지 않고 이미 존재하는 DOM 노드를 참조로 재활용한다.

이 덕분에 React는 초기 렌더링 속도를 크게 개선할 수 있고,
SSR로 렌더된 화면을 깜빡임 없이 자연스럽게 이어받는다.


React StrictMode와 Hydration 점검

React 18의 StrictMode는 Hydration 과정에서도 중요한 역할을 한다.
개발 모드에서만 동작하며, 컴포넌트를 의도적으로 두 번 초기화한다.

왜 ?

부수효과(Side Effect) 가 의도치 않게 중복 실행되거나
Hydration 타이밍과 충돌하는 문제를 조기에 찾아내기 위해서다.

즉, React는
이 코드가 Hydration-safe하게 동작하는가?를 미리 검증하기 위해
useEffect·useState 등의 초기화를 두 번 수행한다.

프로덕션에서는 한 번만 실행되므로 성능 저하는 없다.


Suspense와 Streaming SSR

기존 SSR의 문제는 모든 데이터가 준비될 때까지 서버가 HTML을 보내지 못한다는 점이었다.
React 18에서는 이 문제를 해결하기 위해 Streaming SSR이 도입됐다.

<Suspense> 컴포넌트를 사용하면,
서버는 준비된 부분부터 HTML을 스트리밍으로 전송하고,
아직 준비되지 않은 부분은 fallback UI로 채운다.

<Suspense fallback={<Loading />}>
  <UserProfile />
</Suspense>

서버는 이런 식으로 HTML을 순차적으로 흘려보낸다:

  1. 먼저 Loading UI 전송
  2. 데이터가 도착하면 UserProfile HTML 추가 전송
  3. 브라우저가 두 조각을 합쳐 최종 완성

이 구조 덕분에 사용자는 로딩 중에도 페이지가 즉시 반응하는 경험을 얻는다.


React 19의 Flight — Partial Hydration

React 19에서는 Flight 프로토콜을 중심으로
Partial Hydration(부분 하이드레이션) 이 실험되고 있다.

기존에는 클라이언트 전체를 한 번에 hydrate해야 했지만,
Flight는 서버에서 렌더링된 결과를 JSON 형태로 나누어 전송하고,
클라이언트는 필요한 부분만 복원한다.

// 서버: 컴포넌트 트리를 JSON으로 분해하여 전송
// 클라이언트: 특정 상호작용 발생 시 관련 부분만 Hydrate

이 구조는

  • 불필요한 hydration 비용을 줄이고
  • 상호작용이 필요한 구간만 동적으로 활성화
    하도록 설계되어 있다.
profile
Frontend Developer

0개의 댓글