🍃このブログは移転しました。
3秒後、自動的に移動します・・・。

Next.jsで、サーバー・クライアントで一度だけやりたい処理

たとえば`firebase.initializeApp()`とか、特定のライブラリにSSR時には何もしなくてよいことを伝えるAPIとか。

ドキュメントにもコレだ!という部分がなかったので書いておく。

クライアント

`pages/_app.js`で、`useEffect(fn, [])`でできる。

import React, { useEffect } from "react";

function MyApp({ Component, pageProps }) {
  useEffect(() => { /* ここでやる */ }, []);
  return <Component {...pageProps} />
}

export default MyApp

という感じ。

Advanced Features: Custom `App` | Next.js

この`_app.js`は、`pages`配下のルートのコンテナ的存在で、ドキュメントにも`componentDidCatch()`などに利用しろと書いてあった。

URLが変わってページが切り替わるのはこいつの子であるので、とりあえず一度だけやりたい処理を書く場所としてはわかりよい。

`useEffect()`にすることで、SSR時は実行されないので、クライアントでのみ実行したいことができるといわけ。
必ず子コンポーネントの`useEffect()`よりも先に実行したという場合は、`useEffect()`ではなく、`useLayoutEffect()`にすればよい。(パフォーマンスにはよくない)

サーバー

SSR時のみ実行したい処理を、シュッと書く方法はなさそう。

Server-side only method to ensure server-only code is never sent to the browser · Issue #5354 · vercel/next.js · GitHub

インターネッツから探しだした情報としては、こうすればSSR時かどうかはわかる、と。

const isSSR = typeof window === "undefined";

なのでおなじく`_app.js`のコンポーネント定義の外あたりに書いておくしかないかな・・という感じ。

import React, { useEffect } from "react";

if (typeof window === "undefined") {
  /* ここでやる */
}

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp


2020年にもなってこんな書き方させるってマジ?天下のNextさんが?って思ってたら、それ用のテストまであって本気のご様子だった・・・。

https://github.com/vercel/next.js/blob/canary/test/integration/typeof-window-replace/test/index.test.js

クライアントサイドでのバンドルにも含まれないんですって!!