개발 slecs

라이브 시계 시간 불일치 버그 수정

목차

SSR 환경에서 서버와 클라이언트의 시간 표시가 달라지던 문제를 고쳤다. 라이브 시계 컴포넌트가 서버의 KST(한국 표준시)로 렌더링되면서 접속자의 로컬 타임존과 맞지 않던 것. 마운트 직후 클라이언트 로컬시간으로 즉시 보정하는 방식으로 해결했다.

SSR 하이드레이션과 타임존의 불편한 진실

리액트의 서버 사이드 렌더링을 쓸 때 자주 마주치는 함정이 있다. 서버에서 렌더링한 HTML과 클라이언트에서 렌더링한 결과가 정확히 일치해야 하이드레이션이 성공하는데, 시간이나 로케이션 같은 "실행 환경 의존적" 값이 끼어들면 순식간에 불일치가 생긴다.

이 경우도 그랬다. 라이브 시계는 실시간으로 현재 시간을 표시하는 컴포넌트인데, 서버에서는 당연히 서버의 시간대(KST)를 기준으로 초기 시간을 렌더링한다. 그런데 한국 외 지역의 사용자가 접속했다면? 클라이언트는 현지 시간(예: 미국 동부 시간)으로 하이드레이션 과정을 진행하는데, 이미 렌더링된 HTML의 시간값과 자신이 생성하려던 값이 다르니 React 경고가 울린다.

Warning: Text content did not match. Server: "10:34:22" Client: "22:34:22"

이건 단순 경고일 수도 있지만, 처음 마운트되는 순간 깜빡임이 생기거나, 잘못된 시간이 노출되는 문제로 이어질 수 있다.

클라이언트-서버 시간 갭을 어떻게 메울까

일반적으로 SSR 에서 이런 환경 의존적 값을 다루는 방법은 몇 가지다:

접근 방식 장점 단점
서버에서 타임존까지 포함해 HTML 생성 정확한 초기 렌더 사용자 타임존을 미리 알아야 함
클라이언트 전용 값으로 처리 (hydration skip) 간단함 초기 깜빡임 가능
마운트 직후 클라이언트 시간으로 보정 안정적, 점진적 약간의 지연 가능

이 수정에서는 세 번째 방식을 택했다. 서버에서는 일단 KST 기준으로 초기값을 렌더링해 하이드레이션 성공을 보장하고, 컴포넌트가 마운트되자마자 useEffect 에서 클라이언트의 로컬 시간으로 업데이트하는 식이다. 사용자 입장에서는 깜박거리는 느낌 없이 자신의 로컬 시간이 자연스럽게 표시된다.

변경 내역

src/components/LiveTicker.tsx
- 마운트 직후 로컬 타임존으로 즉시 시간값 갱신하는 로직 추가
- 서버 렌더링 초기값과 클라이언트 업데이트 사이의 불일치를 의도적으로 허용하되, useEffect 타이밍으로 시각적 깜빡임을 최소화

tsconfig.tsbuildinfo
- 빌드 캐시 갱신 (로직 변경에 따른 타입 체크 재실행)

회고: 환경 의존성은 경계 대상

이런 버그는 보통 다음 두 가지 상황에서 나타난다. 하나는 내 개발 환경과 실제 배포 환경(또는 사용자의 환경)이 다를 때고, 다른 하나는 테스트 환경에서 놓친 엣지 케이스를 실서비스에서 만날 때다. SSR 의 경우 둘 다 겹친다.

앞으로도 시간, 로케이션, 화폐 등 "실행 시점과 장소의 영향을 받는 값"을 다룰 때는 초기 설계부터 "서버와 클라이언트가 다를 수 있다"는 가정을 끼워 두기로 했다. 단순히 버그를 고치는 것보다 그 원인이 되는 설계 사고를 인식하는 게 더 중요하다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.