[Next.js] Hydration 오류 해결기

혜연·2025년 5월 24일
0

Next.js

목록 보기
13/20
post-thumbnail

💥 문제 발생

Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used: 

오류가 발생했다.

이 오류는 서버에서 렌더링한 HTML와 클라이언트가 그린 HTML이 달라졌을 때 발생한다.

원인 분석

Next.js의 SSR 흐름은 아래와 같다.

  • 서버에서 먼저 HTML을 렌더링하고 (SSR)
  • 클라이언트에서 이를 받아서 "Hydration"(하이드레이션)을 시도하는데,
  • 이때 두 결과가 달라지면 Hydration 실패

문제가 발생한 코드를 보니

<p className="text-gray-600">
   {new Date(comment.createdAt).toLocaleString()}
<p>

이 부분이었다.
toLocaleString()은 브라우저 환경이나 언어 설정에 따라 결과가 달라질 수 있다.

  • SSR서버에서는 Node.js의 지역 설정에 따라 렌더링하고
  • 클라이언트에서는 사용자 브라우저의 지역 설정을 따라가 불일치가 발생한 것이었다.
new Date().toLocaleString();
// 브라우저가 한국이면 → "2025. 5. 23. 오후 3:10"
// 브라우저가 미국이면 → "5/23/2025, 3:10 PM"
// 서버(Node.js)는? → 서버 OS의 기본 설정 따라감

해결방법

나는 date-fns 라이브러리를 사용해서, 서버와 클라이언트에서 같은 포맷을 사용하도록 해결했다.

<p className="text-gray-600">
    {formatRelativeTime(new Date(comment.createdAt))}
</p>

formatRelativeTime 유틸 함수

import { format, formatDistanceToNowStrict } from "date-fns";
import { ko } from "date-fns/locale";

export function formatRelativeTime(date: Date) {
  const now = new Date();
  const diffInMs = now.getTime() - date.getTime();
  const diffInSec = diffInMs / 1000;  // 1000ms 여서
  const diffInDay = diffInMs / (1000 * 60 * 60 * 24);

  if (diffInSec < 60) {
    return "방금 전";
  }

  if (diffInDay < 3) {
    return formatDistanceToNowStrict(date, { locale: ko, addSuffix: true });
  }

  return format(date, "yyyy.MM.dd");
}

date-fns라이브러리의 formatDistanceToNowStrict을 사용해서 포맷을 맞췄다.

formatDistanceToNowStrict(date, { locale: ko, addSuffix: true })

지금(new Date())과 주어진 date사이의 거리를 단위별(초, 분, 시간, 일..)로 엄격하게 계산해서 "1분 전", "3시간 전"과 같은 문자열을 리턴하는 함수이다.

  • locale: ko → 강제로 한국어 출력
  • addSuffix: true → "전", "후" 같은 접미사 붙이기

결과

  • Hydration 오류 해결 🎉
  • 사용자에게 더 친절한 시간 표현 제공
  • SSR + Client 환경에서의 날짜 처리 경험

Next.js의 하이브리드 렌더링 구조에서 자주 발생하는 이슈라고 한다.
첫 데모 프로젝트에서 하이브리드 이슈를 해결하면서, SSR이 어떻게 동작하는지 하나씩 체감하는 중

0개의 댓글