概要
Nuxt.jsはデフォルトでサーバサイドレンダリングが有効になっているため、サーバサイドでは存在しないwindow, localStorage, sessionStorageなどのオブジェクトを参照しようとするとエラーになってしまう。
Nuxt.jsの場合はnuxt.config.tsでssr: false
を指定することでSSRを無効にすることができるが、Next.jsの場合はnext/dynamicを使ってコンポーネントを動的にインポートする必要がある。
エラーの例
const snapshotsJson = localStorage.getItem('hoge');
はReferenceError: localStorage is not definedとなる。
また、cookie, localStorage, sessionStorageなどブラウザで保持している値をstateに代入すると、サーバサイドとブラウザでのレンダリング結果に差分が発生してしまうため、以下のようなエラーとなることがある。
Unhandled Runtime Error
Error: Text content does not match server-rendered HTML.
Warning: Text content did not match. Server: “” Client: “0”
See more info here: https://nextjs.org/docs/messages/react-hydration-error
解決方法
特定の場所のみエラーを回避するのであれば、以下のように書くことができる。
if (typeof localStorage !== "undefined") {
console.log(localStorage.getItem('hoge'))
}
Next.jsアプリ全体やコンポーネント単位でエラーを回避する場合は、next/dynamicを使ってコンポーネントを動的にインポートする必要がある。
next/dynamicはオプションでssr: false
を指定するとSSRは無効となりSPA(CSR)として動作する。
_app.jsx(_app.tsx)にて、ssr: false
でインポートしたコンポーネントで全体を囲むとNext.jsアプリ全体でSSRが無効となる。
import type { AppProps } from 'next/app'
import dynamic from 'next/dynamic';
const Wrapper = dynamic(() => import('./Wrapper'), { ssr: false });
export default function App({ Component, pageProps }: AppProps) {
return (
<Wrapper>
<Component {...pageProps} />
<Wrapper>
);
}
import { FC, ReactNode } from 'react';
type WrapperProps = {
children?: ReactNode;
};
const Wrapper: FC<WrapperProps> = ({ children }) => {
return <div className="wrapper">{children}</div>;
};
export default Wrapper;
コメント