・はじめに
Next.jsは、サーバーサイドレンダリング(SSR)や静的サイト生成(SSG)を活用することで、高速なWebアプリケーションを構築できるフレームワークです。しかし、クライアントとサーバーのレンダリング結果が一致しない場合に発生する「Hydration Error(ハイドレーションエラー)」に悩まされることがあります。
この記事では、Hydration Errorの原因と、それを回避するためのベストプラクティスを詳しく解説します。
・Hydration Errorとは?
Hydration Errorとは、Next.jsでサーバー側とクライアント側のレンダリング結果が一致しないときに発生するエラーです。主に以下のような状況で発生します。
・サーバーとクライアントのHTMLの不一致
・クライアント側で動的に変更されるコンテンツの影響
・レンダリング時の副作用による影響
1.エラーメッセージの例
Warning: Text content did not match. Server: "Hello" Client: "Hello, World!"
この警告は、サーバー側でレンダリングされたテキストと、クライアント側でレンダリングされたテキストが異なる場合に表示されます。
・Hydration Errorを回避する方法
1.クライアントサイドのみで実行するコンポーネントの処理
サーバーとクライアントのレンダリング結果を一致させるため、クライアントサイドのみで実行するべき処理を適切に分離することが重要です。
useEffect
を活用する
クライアント側でのみ実行したい処理は、useEffect
フックを使うことで回避できます。
import { useState, useEffect } from 'react';
const ClientOnlyComponent = () => {
const [message, setMessage] = useState('');
useEffect(() => {
setMessage('Hello, World!');
}, []);
return <div>{message}</div>;
};
export default ClientOnlyComponent;
この場合、サーバーでは空のdiv
がレンダリングされ、クライアント側でHello, World!
が表示されます。
2.useClient
ディレクティブを利用する(App Routerの場合)
Next.js 13以降のApp Routerでは、use client
を使用してクライアントサイドでのみレンダリングすることが可能です。
"use client";
import { useState } from 'react';
const ClientComponent = () => {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>Click me: {count}</button>
);
};
export default ClientComponent;
このディレクティブを使用すると、そのコンポーネントはクライアント側でのみレンダリングされるため、サーバーとの不一致が発生しません。
3.クライアントとサーバーの初期値を統一する
サーバーとクライアントで異なるデータを使用すると、Hydration Errorが発生します。たとえば、Math.random()
やDate.now()
を直接JSXに書くと問題が生じます。
useState
を使った統一例
import { useState, useEffect } from 'react';
const RandomNumber = () => {
const [randomNumber, setRandomNumber] = useState(0);
useEffect(() => {
setRandomNumber(Math.random());
}, []);
return <p>Random Number: {randomNumber}</p>;
};
export default RandomNumber;
サーバー側ではデフォルト値(0)がレンダリングされ、クライアント側でuseEffect
により値が変更されるため、一貫性が保たれます。
4.suppressHydrationWarning
の使用
Next.jsでは、意図的にHydration Errorを無視したい場合にdangerouslySetInnerHTML
を使用する代わりに、suppressHydrationWarning
を設定できます。
const HydrationWarningComponent = () => {
return <p suppressHydrationWarning>{new Date().toString()}</p>;
};
この方法はあくまで一時的な対処法であり、可能な限り適切な方法で修正することを推奨します。
5.動的データの取得を適切に処理する
データ取得のタイミングによってはHydration Errorが発生するため、適切に処理する必要があります。
サーバーサイド取得(SSR)
export async function getServerSideProps() {
return {
props: {
timestamp: new Date().toISOString(),
},
};
}
const ServerTimestamp = ({ timestamp }) => {
return <p>Server Time: {timestamp}</p>;
};
export default ServerTimestamp;
SSRを利用することで、サーバー側とクライアント側で一致したデータを渡せます。
・まとめ
Hydration Errorは、サーバーとクライアントのレンダリング結果の不一致が原因で発生します。これを回避するために、
- クライアントサイドでのみ実行すべき処理を
useEffect
やuseClient
で分離 - サーバーとクライアントの初期値を統一
suppressHydrationWarning
の適切な使用- データ取得のタイミングを適切に管理
などの対策を講じることが重要です。
Next.jsを活用する上でHydration Errorは避けて通れない問題ですが、適切な実装を行うことでスムーズな開発が可能になります!