devlog

【Next.js】ブラウザのタイムゾーンを変えたら Hydration Error が起きた

2024-02-09

概要

  • Next.js Pages (SSG) で、ブラウザのタイムゾーンを変えたら Hydration Error が起きた
  • Text content does not match server-rendered HTML というエラー
  • 原因は日時をフォーマットしている箇所
  • タイムゾーンを考慮し忘れていた。ブラウザのタイムゾーンを使っていた様子

状況: 日付文字列をフォーマットしたい

ISO8601 形式の日付文字列から YYYY-MM-DD を取り出し表示させていた。

import dayjs from 'dayjs' export default function Page() { const created = dayjs('2024-02-08T00:00:00+09:00').format('YYYY-MM-DD') return <>date: {created}</> }

なんともない処理。ごく普通に表示される

date: 2024-02-08

 
ところが..

ブラウザのタイムゾーンを America/New_York へ変更すると Hydration Error が起きた

Error: Text content does not match server-rendered HTML.
Warning: Text content did not match. Server: "2024-02-08" Client: "2024-02-07"
See more info here: https://nextjs.org/docs/messages/react-hydration-error

サーバとブラウザとで日付部分の文字列がミスマッチしているよ、と指摘されている

原因: ブラウザのタイムゾーンを使用してそう

dayjs で日付文字列をパースするときブラウザのタイムゾーンを使用してそうだと分かった

const created = dayjs('2024-02-08T00:00:00+09:00').toString() // ブラウザのタイムゾーンが Asia/Tokyo では console.log(created) // Wed, 07 Feb 2024 15:00:00 GMT // ブラウザのタイムゾーンが America/New_York では console.log(created) // Wed, 07 Feb 2024 01:00:00 GMT

対応: Intl.DateTimeFormat を使う

dayjs では timezone まわりの処理がプラグインとして切り出されている

個人サイトのため正直対応が面倒だったのと、もともと dayjs で大した処理をしていなかったので、 いっそのこと Intl.DateTimeFormat を使う実装へ変えてみた

export default function Page() { const datefmt = new Intl.DateTimeFormat('ja-JP', { year: 'numeric', month: '2-digit', day: '2-digit', timeZone: 'Asia/Tokyo', }); const created = datefmt.format(new Date('2024-02-08T00:00:00+09:00')).replace(/\//g, '-'); return <>date: {created}</> }

感想

  • 日付周りの話はあるあるだと思う。
  • どちらかと言うとエラーをどうやって検知すれば良いか悩ましい
  • こういうエラーはローカル開発環境で気づくのが難しそう
  • 作成日
    2024-02-09
  • 更新日
    2024-02-09