SSR/SGではレンダリング時にブラウザの機能を使えない
サーバサイドでの処理の過程ではクライアントサイド、つまりブラウザ上でのみ実行可能な機能は利用できません。具体例は以下の通りです。- Windowの参照
- Cookieの参照
- localStrageの参照
- sessionStorageの参照
Next.jsのページのレンダリングはデフォルトでPre-rendering、つまりSSR(Server-side Rendering)もしくはSG(Static Generation)ですので1、Next.jsにおいて以下のコードは意図した結果になりません。
import type { NextPage } from "next";
import Cookies from 'js-cookie'
const Example: NextPage = () => {
// window.documentによる文書の参照
const element = window.document.getElementById('example'); // ReferenceError: window is not defined
// window.alertによる警告ダイアログ表示
window.alert("Hello world!"); // ReferenceError: window is not defined
// Cookieのデータ取得(exampleというnameのvalueを取得する場合)
console.log(Cookies.get('example')); // undefined
// localStorageのデータ取得(exampleというnameのlocalStrageを取得する場合)
console.log(localStorage.getItem("example")); // ReferenceError: localStorage is not defined
// sessionStorageのデータ取得(exampleというnameのsessionStrageを取得する場合)
console.log(sessionStorage.getItem("example")); // ReferenceError: sessionStorage is not defined
return <div id='example'>Example</div>;
};
export default Example;
解決方法: SSR/SGでブラウザの機能を活用したい場合は副作用で実行する
副作用とは「JSXあるいはTSXからUIを構築する処理」以外に関する処理のことをいいます。
副作用の実行は、関数コンポーネントであれば副作用フックと呼ばれるuseEffectやuseSWR、クラスコンポーネントであればcomponentDidMount・componentDidUpdate・componentWillUnmountで行います。
副作用はマウント後に実行されるため、Pre-renderingのページであってもブラウザ上でのみ実行可能な機能を利用できます。具体例は以下の通りです。
import type { NextPage } from "next";
import Cookies from 'js-cookie'
import { useEffect } from "react";
const Example: NextPage = () => {
useEffect(() => {
// window.documentによる文書の参照
const element = window.document.getElementById('example');
console.log(element?.innerText); // Example
// window.alertによる警告ダイアログ表示
window.alert("Hello world!"); // 警告ダイアログが表示される
// Cookieのデータ取得
Cookies.set('example', 'exampleCookie');
console.log(Cookies.get('example')); // exampleCookie
// localStorageのデータ取得
localStorage.setItem('example', 'exampleLocalStrage');
console.log(localStorage.getItem("example")); // exampleLocalStrage
// sessionStrageのデータ取得
sessionStorage.setItem('example', 'exampleSessionStrage');
console.log(sessionStorage.getItem("example")); // exampleSessionStrage
}, []);
return <div id='example'>Example</div>;
};
export default Example;
なお、Next.jsでブラウザの機能を利用する場合は副作用以外にtypeof window
、process.browser
、dynamic import
を活用する方法もあります。
詳細解説は Next.jsのSSR回避(クライアントサイドでのみ実行)の実装パターン集 で紹介しています。
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!