Next.js で SSR を無効化する方法(next/dynamic)
January 12, 2022
例えば Next.js でこんなコンポーネントを表示しようとしても、
const Component = () => {
return <p>This is {window.location.href}</p>;
};
ReferenceError: window is not defined
になります。
これを回避するには、useEffect
の中で window
オブジェクトにアクセスする必要があります。回避と書きましたがこれが正しい対応方法です。
でも、そもそもこの部分は CSR 前提で作っているから SSR は使わないのよ、と言う場合は SSR を無効化することもできます。
next/dynamic の Dynamic Import を使いましょう #
こんな感じでコンポーネントが export
されているとします。
components/index.tsx
const Component = () => {
return <p>This is {window.location.href}</p>;
};
export { Component };
変更前 #
それを index
ページが import
して表示しているとします。このままだと先程のエラーが出てしまいます。
pages/index.tsx
import { Component } from 'src/components';
export default Component;
変更後 #
では index
ページを SSR しないように設定します。それが以下です。
pages/index.tsx
import dynamic from 'next/dynamic';
export default dynamic(
async () => {
const module = await import('src/components');
return module.Component;
},
{ ssr: false }
);
こうすると dynamic import されたコンポーネントは必ず CSR でのみ実行されます。
useEffect
を挟まずとも window
オブジェクトにアクセス可能です。他には Next.js の router.query
が初回に undefined
を返すこともなくなります。一発でクエリストリングが取得できます。
dynamic import はコンポーネント単位で行えるため、ページの一部分のみを dynamic import することでその部分だけを SSR 無効化させることも可能です。
アプリ全体を CSR 化してしまうなら #
アプリ全体を一括で CRS 化するのであれば、CSR 用の高階コンポーネントを作成して _app.tsx
で他のコンポーネントを囲ってしまうのが楽です。
components/CSRInner.tsx
const CSRInner = ({ children }: { children: JSX.Element | JSX.Element[] }) => {
return <>{children}</>;
};
export default CSRInner;
components/CSR.tsx
import dynamic from 'next/dynamic';
const CSR = dynamic(() => import('./CSRInner'), { ssr: false });
export default CSR;
pages/_app.tsx
import CSR from 'src/components/CSR';
import type { AppProps } from 'next/app';
const App = ({ Component, pageProps }: AppProps) => {
return (
<CSR>
<Component {...pageProps} />
</CSR>
);
};
export default App;
リファレンス #
公式のわかりやすいドキュメントがありますので、後の詳細はそちらをぜひご参照ください。