Next.jsは、サーバサイドとクライアントサイドでの実行を適切に切り替えてくれます。しかし、切り替えを理解しないまま、Firestoreの読み書きを含むコードを書くと、思わぬトラブルに直面することがあります。gpt.icon

  • Next.jsの魅力は、同じ言語でクライアントサイドとサーバサイドの両方を書けることです。ただし、その前提は、人間が「どの部分がどこで実行されるのか」を正確に理解していることです。

わからないのでGPT4に聞いたら盲点がわかった、なるほど両方で実行される部分があるのかnishio.icon

  • 1: Anything in getServerSideProps or getInitialProps runs on the server-side. These functions are used for server-side rendering. They are run on the server when a request is made to the page.

  • 2: Anything in getStaticProps or getStaticPaths also runs on the server-side. These functions are used for static generation. They are run at build time on the server.

  • 3: Any other code in your React components, outside the above functions, will run on both server and client side.

  • 4: Code in useEffect hooks runs on the client-side only.

  • 5: Code in event handlers (like onClick, onSubmit, etc.) runs on the client-side only.

「サーバサイドとクライアントサイドのどっちで実行される?」は誤った二分法

昔、生のReactを使ってたころはFirebaseの初期化のコードをモジュールに書いて、それを各所でインポートして使うことで呼び出し前に1回初期化のコードが走ってることを保証していた

  • 生のReactは全部クライアントサイドで走るので問題はなかった
  • 今回同じやり方をしたらgetAnalyticsの初期化でwindowがない旨のエラーになった
    • このエラーをみて「サーバサイドで実行されてる」と思った
    • そこから「クライアントサイドで実行されていない」と思ったのが勘違い
    • 「誤った二分法」にはまっている
  • 「誤った二分法」にはまって前提がおかしくなっていることに気づかないままGPTに「この初期化のコードがクライアントサイドで実行されることを保証したい」って言った
    • そうするとuseEffectの中でダイナミックインポートしてモジュールをsetStateするコードを生成し始めた
    • 確かにそれならクライアントサイドでしか動かないけど「いや、流石にその設計はおかしいのでは?」となった
    • ここで、自分の理解の誤りを疑った
  • GPT4は便利だけど、正しくない理解で適切でない要求を伝えると、その要求をなんとかしようとして複雑なコードを生成してしまう
    • GPT4が生成できるくらい広く使われてるNext.jsとFirestoreの組み合わせで「useEffectの中でダイナミックインポート」が必須なわけがない

今回のケースではgetAnalyticsを初期化で呼ぶ必要はない

  • 必要なところで呼べばよい
  • トリッキーなコードを書く必要はまったくなかった