コンテンツにスキップ
DocsErrorsuseSearchParams() を Suspense 境界なしで使用

useSearchParams() を Suspense 境界なしで使用

このエラーが発生した理由

useSearchParams() を Suspense 境界なしで検索パラメータを読み取ると、ページ全体がクライアントサイドレンダリングにオプトインされます。これにより、クライアントサイド JavaScript がロードされるまでページが空白になる可能性があります。

修正方法

意図に応じて、いくつかの選択肢があります。

  • ルートを静的に生成したままにするには、useSearchParams() を呼び出す最小のサブツリーを Suspense でラップします。たとえば、その使用法を子クライアントコンポーネントに移動し、Suspense でラップされたそのコンポーネントをレンダリングすることができます。これにより、静的なシェルが維持され、完全な CSR バイラウトが回避されます。
  • ルートを動的にレンダリングするには、Server Component (例: Page またはラップする Layout) で connection 関数を使用します。これは、着信リクエストを待機し、それ以下のすべてをプリレンダリングから除外します。
app/page.tsx
import { connection } from 'next/server'
 
export default async function Page() {
  await connection()
  return <div>...</div>
}
  • connection API が利用可能になる前は、Server Component の page.tsx または layout.tsxexport const dynamic = 'force-dynamic' を設定することで、ルートをオンデマンドレンダリングにオプトインしていました。'use client' が付いた Client Component の page.tsxdynamic を設定しても効果がないことに注意してください。
app/layout.tsx
export const dynamic = 'force-dynamic'
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return children
}
  • または、Server Component の Page は searchParams 値を Client Component に渡すことができます。Client Component では、React の use() でアンラップできます (周囲に Suspense 境界があることを確認してください)。「何を使用し、いつ使用するか」を参照してください。
app/page.tsx
import { Suspense } from 'react'
import ClientSearch from './client-search'
 
export default function Page({
  searchParams,
}: {
  searchParams: Promise<{ q?: string }>
}) {
  return (
    <Suspense fallback={<>...</>}>
      <ClientSearch searchParams={searchParams} />
    </Suspense>
  )
}
app/client-search.tsx
'use client'
 
import { use } from 'react'
 
export default function ClientSearch({
  searchParams,
}: {
  searchParams: Promise<{ q?: string }>
}) {
  const params = use(searchParams)
  return <div>Query: {params.q}</div>
}
  • Page を再度 Server Component にし、クライアント専用コード (useSearchParams を使用するもの) を子 Client Component に分離することを検討してください。
app/search.tsx
'use client'
 
import { useSearchParams } from 'next/navigation'
import { Suspense } from 'react'
 
function Search() {
  const searchParams = useSearchParams()
 
  return <input placeholder="Search..." />
}
 
export function Searchbar() {
  return (
    // You could have a loading skeleton as the `fallback` too
    <Suspense>
      <Search />
    </Suspense>
  )
}

無効にする

注意: これは Next.js バージョン 14.x でのみ利用可能です。14 より上のバージョンを使用している場合は、上記のアプローチで修正してください。

このルールの無効化は推奨されません。ただし、必要な場合は、next.config.jsmissingSuspenseWithCSRBailout オプションを false に設定することで無効にできます。

next.config.js
module.exports = {
  experimental: {
    missingSuspenseWithCSRBailout: false,
  },
}

この構成オプションは、将来のメジャーバージョンで削除されます。