Next.js
React 날짜 표시가 서버와 브라우저에서 달랐던 hydration 실수
서버 렌더링한 날짜가 브라우저에서 다른 문자열이 되어 hydration 경고가 난 상황에서, 시간대와 포맷 책임을 분리한 방법입니다.
콘솔 경고의 숫자 하나가 힌트였다
게시물 카드의 날짜가 어떤 사용자에게는 하루 전으로 보였고 hydration 경고도 났다. DB의 UTC ISO 문자열은 정상이었다. 서버는 UTC, 브라우저는 KST를 기본값으로 삼아 각자 날짜를 만든 것이 문제였다.
표시 기준을 함수에 적었다
처음에는 toLocaleDateString()만 호출했다. 실행 위치에 따라 결과가 달라지므로 서버 렌더링에는 위험했다.
export function formatKoreanDate(value: string) {
return new Intl.DateTimeFormat('ko-KR', {
timeZone: 'Asia/Seoul',
year: 'numeric', month: 'long', day: 'numeric',
}).format(new Date(value));
}
<time dateTime={post.publishedAt}>{formatKoreanDate(post.publishedAt)}</time>
이제 서버와 브라우저가 locale과 시간대를 같은 입력으로 받는다. suppressHydrationWarning으로 경고를 숨기는 방법은 실제로 다른 날짜를 읽는 문제를 해결하지 못해 쓰지 않았다.
현지 시간이 필요한 화면은 다르다
예약 시간처럼 사용자의 현지 시간이 의미 있는 화면이라면 KST 고정이 답이 아니다. UTC를 보여 준 뒤 클라이언트에서 바꾸거나, 표시가 달라질 수 있음을 설계에 포함해야 한다.
- 저장 값에 시간대가 포함됐는지 확인한다.
- KST 고정인지 현지 시간인지 먼저 정한다.
- 자정 전후 데이터로 서버와 브라우저를 함께 시험한다.
날짜는 짧은 문자열이지만 서버와 사용자의 위치가 만나는 지점이다. 경고를 없애는 대신 표시 규칙을 코드에 남겼다.