React SSR 하이드레이션 문제 해결 방법
서버 사이드 렌더링 이후 발생하는 하이드레이션 불일치의 원인 진단, 점검 항목, 코드 패턴과 성능 최적화를 중심으로 한 해결책
목차
소개
서버 사이드 렌더링(SSR)은 초기 로드 성능을 높인다. 그러나 클라이언트에서 React가 DOM을 하이드레이트할 때 불일치가 생기면 콘솔 경고와 UI 깜박임이 발생한다. 이 글은 초보자도 이해할 수 있도록 하이드레이션 오류의 원인과 실무에서 쓰기 좋은 해결법을 정리한다.
하이드레이션 불일치의 주요 원인
서버와 클라이언트 렌더링 결과 차이
서버에서 렌더된 HTML과 클라이언트에서 생성한 가상 DOM이 다르면 불일치가 발생한다. 흔한 이유는 랜덤값, 현재 시간, 브라우저 전용 API 사용 등으로 인한 비결정적 출력이다.
비동기 데이터 패칭 타이밍
SSR 시점에는 데이터가 채워져 있지만 클라이언트에서 상태 초기화가 늦으면 서로 다른 UI가 렌더된다. 이로 인해 react hydration mismatch 해결이 필요해진다.
브라우저 전용 코드의 서버 실행
window, document, localStorage 같은 브라우저 전용 API를 서버에서 호출하면 오류 또는 다른 결과가 나온다. 서버 전용 렌더 출력과 클라이언트 초기화가 달라질 수 있다.
스타일/클래스 일관성 문제
CSS-in-JS나 스타일시트 삽입 순서가 서버와 클라이언트에서 달라지면 클래스명이 일치하지 않아 하이드레이션 오류가 발생할 수 있다.
점검 체크리스트
- 콘솔의 구체적 경고 메시지 확인
- 서버와 클라이언트 HTML 차이 비교
- 랜덤값, 날짜, Math.random 사용 위치 파악
- 브라우저 전용 API 사용 여부 확인
- 스타일 라이브러리의 SSR 가이드 준수 여부 점검
- 데이터 페칭 전략(SSR에서 전달하는 초기 상태) 검토
구체적 해결 전략
결정적 렌더링 보장
서버와 클라이언트 모두 동일한 입력으로 동일한 출력을 내도록 만든다. 랜덤값이나 날짜는 서버와 클라이언트에 같은 초기값을 주거나 클라이언트에서만 설정한다. 이렇게 하면 ssr 하이드레이션 오류 react 상황을 줄일 수 있다.
클라이언트 전용 UI는 클라이언트에서만 렌더
서버에서 렌더할 필요가 없는 부분은 클라이언트 전용으로 처리한다. 예: 광고, 서드파티 위젯, 시간 표시. React에서는 조건부로 렌더하거나 useEffect로 초기화한다.
suppressHydrationWarning 사용
일부 텍스트가 서버와 클라이언트에서 달라질 수밖에 없는 경우에는 element에 suppressHydrationWarning 속성을 사용한다. 단, 남용은 피한다.
key 속성으로 재조정
동적인 리스트나 상태 변화로 DOM 구조가 바뀌면 적절한 key를 사용해 React가 정확히 업데이트하도록 돕는다.
데이터 일관성 유지
서버에서 클라이언트로 초기 상태를 주입(state hydration)을 명확히 한다. 초기 렌더에 필요한 데이터를 미리 전달하면 하이드레이션 과정에서 상태 불일치가 줄어든다.
코드 예제
클라이언트에서만 렌더해야 할 요소를 useEffect로 처리하는 예시.
import React, { useEffect, useState } from 'react'
function ClientOnlyClock() {
const [time, setTime] = useState(null)
useEffect(() => {
setTime(new Date().toLocaleTimeString())
const id = setInterval(() => {
setTime(new Date().toLocaleTimeString())
}, 1000)
return () => clearInterval(id)
}, [])
// 서버에서는 null이 렌더되고 클라이언트에서만 시간 표시
return <div>{time ? time : '...' }</div>
}
export default ClientOnlyClock
서버와 클라이언트 출력이 다른 텍스트에 suppressHydrationWarning 적용 예시.
function UserGreeting({ name }) {
// 서버에서는 '방문자'가 렌더되고 클라이언트에서 name이 채워지는 경우
return <span suppressHydrationWarning>{name ? `안녕하세요, ${name}` : '안녕하세요, 방문자'}</span>
}
hydration performance react: 성능 최적화 팁
하이드레이션은 초기 상호작용 가능성에 영향을 준다. 성능을 개선하려면 우선순위를 나누고 불필요한 하이드레이션을 지연시킨다.
- React 18의 hydrateRoot와 스트리밍 SSR을 활용해 초기 페인트를 빠르게 처리
- 중요하지 않은 컴포넌트는 클라이언트에서 지연 렌더링
- startTransition으로 저우선 작업을 분리해 사용자 상호작용 우선 처리
- 클라이언트 번들 크기 줄이기: 트리쉐이킹, 코드 분할
실무에서의 권장 흐름
- 문제 발견: 콘솔 메시지와 서버/클라이언트 HTML 비교
- 원인 분류: 데이터, 랜덤, 브라우저 API, 스타일
- 해결 적용: 결정성 확보, 클라이언트 전용 처리, suppressHydrationWarning 최소 적용
- 성능 점검: hydrate 전략, 코드 분할, 우선순위 관리
요약 및 체크포인트
하이드레이션 오류는 대부분 서버와 클라이언트 출력 불일치에서 시작한다. 먼저 차이를 찾아 원인을 좁히고, 결정적 렌더링과 데이터 일관성으로 해결한다. 필요할 때 클라이언트 전용 렌더링을 분리하고 suppressHydrationWarning을 신중히 사용한다. 마지막으로 hydration performance react 관점에서 스트리밍 SSR과 우선순위 관리를 검토하면 초기 상호작용 경험을 개선할 수 있다.