クライアントサイドでだけ動作するライブラリをNext.jsで導入する
投稿日: 2025年05月03日
オリジナルアプリ第2弾である「Canvas Battle」は、UIライブラリもりもりの仕上がりにしましたが、それが仇となって悩んだことを記録します。
当たり前やん!だったらすみません👏
Next.jsの魅力の一つとして、SSR対応で安全・高速なレンダリングができること!があります。しかし私はUIの楽しさを優先して、今回「react-custom-roulette」ライブラリを使ってルーレットを表示させることにしました。
こんなの↓
React Custom Roulette
はじめ、ルーレットを単純にコンポーネントとして書きました。
すると以下のエラーが発生💦
⨯ ReferenceError: window is not defined
つまり、react-custom-roulette
がSSRに非対応であることが原因。中で window
を使っているため、サーバー側でレンダリングしようとするとクラッシュするとのこと。
ちなみに"use client";宣言してもだめだったんですよね。😨
分からない。。
ふぇ?🤯
古いライブラリだから?
もう結構コンポーネント出来上がったよ、、😨
別のライブラリ探す?それとも一から自作?!
一回自分がクラッシュしました💣
いろいろ葛藤し、調べたら以下で解決しました✨
https://nextjs.org/docs/pages/guides/lazy-loading#with-no-ssr
①作ったコンポーネントをわかりやすく「XXXClientOnly.tsx」と命名しなおす。
const RouletteClientOnly: React.FC<Props> = ({ mustSpin, onStop }) => {
// コンポーネント内容
};
export default RouletteClientOnly;
②新たに「XXX.tsx」を作りラップする。その時、以下のようにdynamic import + ssr: false を使って クライアント限定で読み込む。
import dynamic from "next/dynamic";
const Roulette = dynamic(() => import("./RouletteClientOnly"), {
ssr: false,
});
export default Roulette;
以下のように同じディレクトリに書きました!
Next.jsの dynamic() 関数を使うことで、
「このコンポーネントはクライアント側でだけ読み込んでね」と指示ができる!
③親ページにimportするのは「XXX.tsx」。ここはいつも通り(propsも!)でOK!
"use client";
import Roulette from "../_components/Roulette";
<Roulette
mustSpin={mustSpin}
spinKey={spinKey}
onStop={handleCpuStop}
/>
簡単に対処できてほっとしました😭✨
ふと新たな疑問が…
「SSRに非対応なライブラリって、やっぱり使わない方がいいの?」
AIに相談してみたところ、以下の答えを得ました👇
間違ってたら教えてください。。。
結論:使ってもOK!でも「使いどころと影響範囲」を理解して使うのがベスト。
window
や document
、localStorage
、navigator
などブラウザ限定のAPIを直接使っているライブラリ
サーバー側には存在しないため、SSR時にエラーになる
でも、「クライアント限定UI」なら安心して使える!
例:
🌀 ルーレット
🎮 ゲーム演出
🎨 モーダル・ドロップダウンメニュー
📊 グラフ・アニメーション など
ユーザーの操作に応じて動く要素なら、SSRにこだわる必要はありません。
ゲーム系アプリにぴったりな react-custom-roulette
を無事使うことができて一安心🥲とはいえ、もっと良い方法があれば、ぜひお手柔らかに教えてください🙏
今回の経験のように、学んだことや工夫した点をこれからもアウトプットしていけたらと思います!