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>
}connectionAPI が利用可能になる前は、Server Component のpage.tsxまたはlayout.tsxにexport const dynamic = 'force-dynamic'を設定することで、ルートをオンデマンドレンダリングにオプトインしていました。'use client'が付いた Client Component のpage.tsxでdynamicを設定しても効果がないことに注意してください。
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.js で missingSuspenseWithCSRBailout オプションを false に設定することで無効にできます。
next.config.js
module.exports = {
experimental: {
missingSuspenseWithCSRBailout: false,
},
}この構成オプションは、将来のメジャーバージョンで削除されます。
便利なリンク
役に立ちましたか?