みかづきブログ・カスタム

基本的にはちょちょいのほいです。

Next.js(14.2.15)のAppRouterでuseSearchParamsを使う際はSuspenseで境界を指定する 💻

公式ドキュメントに書いてある通りなのですが、ほんのりハマったのでメモ。

nextjs.org

ことの発端

src/app/page.tsx

import { ServerComponent } from '@/components/ServerComponent';

export default function Home() {
  return (
    <ServerComponent />
  );
}

src/components/SeverComponent

import { ClientComponent } from '@/components/ClientComponent';

export function ServerComponent() {
  return (
    <ClientComponent />
  );
}

src/components/ClientComponent

'use client';

import { useSearchParams } from 'next/navigation';

export function ClientComponent() {
  const searchParams = useSearchParams();

  return (
    <div>
      <p>timestamp: { searchParams.get('timestamp') }</p>
    </div>
  );
}

こんな感じのサイトを作っていた際、

yarn dev

では問題が起こらないのですが、

yarn build

実行時に、

useSearchParams() should be wrapped in a suspense boundary at page "/". Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout

と、エラーが発生しました。

提示されたURL に目を通してみると、

Suspenseを使わずにuseSearchParamsを使うと、ページ全体がクライアント側レンダリングに設定されるということが判明。
確かにURLが決まるまでレンダリングされる内容が決まらないことは理解できるのですが、'use client'でクライアントコンポーネントにしていてもページ全体に影響を及ぼすようです。

解決策

Suspenseを設定すればOKです。

今回の場合は、

src/components/SeverComponent

import { Suspense } from 'react';
import { ClientComponent } from '@/components/ClientComponent';

export function ServerComponent() {
  return (
    <Suspense>
      <ClientComponent />
    </Suspense>
  );
}

とすれば良い気がします。

リポジトリ

github.com