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 まわりの処理がプラグインとして切り出されている
- ドキュメント ... https://day.js.org/docs/en/timezone/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