Reactのtree hydratedエラーの解決方法
React Router v7を使っていたところ、次のようなエラーがブラウザのコンソールに表示されました。
A tree hydrated but some attributes of the server rendered HTML didn't match the client properties. This won't be patched up. This can happen if a SSR-ed Client Component used:
- A server/client branch `if (typeof window !== 'undefined')`.- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.- Date formatting in a user's locale which doesn't match the server.- External changing data without sending a snapshot of it along with the HTML.- Invalid HTML tag nesting.
It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.
https://react.dev/link/hydration-mismatch
本記事では筆者が遭遇したケースでのtree hydrated
の解決方法を紹介します。
hydration関係について知らない方は、みんちゃんさんによる記事Next.js で Hydration Error が起きる理由と解決方法をご覧ください。
状況
- React Router v7でSSRをしている
- 上記のリストに書かれているような処理はしてない
- Firefoxのみで発生
コンソールをよく見てみる
よくコンソールを見ると、エラーの詳細としてdiffが出力されてます。
... <Router basename="/" location={{pathname:"...", ...}} navigationType="POP" navigator={{...}}> <DataRoutes routes={[...]} future={{...}} state={{...}}> <RenderErrorBoundary location={{pathname:"...", ...}} revalidation="idle" component={<Layout>} error={undefined} ...> <RenderedRoute match={{params:{}, ...}} routeContext={{...}}> <Layout> <html lang="ja"> <head> <meta> <meta> <Meta> <Links> <style dangerouslySetInnerHTML={{ __html: "\n/* /app/styles/reset.css */\n/* html\r\n-------------------------------------------..." __html: "\n/* /app/styles/reset.css */\n/* html\n---------------------------------------------..."
上記では分かりやすく色をつけていますが、実際には全部同じ色で書かれています。そのため筆者は気づくまでに時間がかかりました。
原因
diffをよく見てみると、改行コードが\n
と\r\n
で違っていました。
__html: "\n/* /app/styles/reset.css */\n/* html\r\n---..."__html: "\n/* /app/styles/reset.css */\n/* html\n-----..."
どうやら改行コードがCRLFのものをFirefoxで読み込んだときにLFに変換されたことで「差が生じたよ」といわれているようです。
該当するreset.css
は他の開発者の方からいただいたCSSファイルをコピーしたものです。
解決法
まずは他にもCRLFのものがあるのではと思って確認しました。file
コマンドでCRLFかどうかが分かります。
file app/**/*.css | grep CRLF
ファイルごとにCRLFからLFへ置換しました。今回はawkを使いました。
awk '{ sub(/\r$/, ""); print }' app/styles/reset.css > app/styles/reset.css.lf \ && mv app/styles/reset.css.lf app/styles/reset.css
以上、tree hydrated
のエラーの解決方法でした。
なぜFirefoxのみで発生したのかについては分からなかったため、分かり次第追記します。