Next.jsにおいてSSRを回避し、useLayoutEffectなどを正常に使用する方法について記載します。
dynamicを使用する
dynamicで{ssr: false}を指定することでSSRを回避できます。
const Sample = dynamic(() => import('../components/Sample'), { ssr: false })
Suspenseを使用する
以下のように記述するとクライアント側で
<Suspense fallback={<Loading />}>
  <Sample />
</Suspense>
function Sample() {
  if (typeof window === 'undefined') {
    throw Error('Sample should only render on the client.');
  }
  // ...
}
SSRではエラーとなり、最も近いSuspenseのfallbackに指定したLoadingが表示されます。
クライアントで正常に処理が完了するとSampleが表示されます。
isMounted stateを使用する
以下のように記述するとコンポーネントがハイドレーションの後にのみレンダリングされます。
export function Sample() {
  const [isMounted, setIsMounted] = useState(false)
  useEffect(() => {
    setIsMounted(true)
  }, [])
  return isMounted ? <RealContent /> : <FallbackContent />
}
useEffectはクライアントでのみ実行されるため、SSRではFallbackContentがレンダリングされ、useEffectが実行されるとRealContentが表示されます。
