コンテンツへスキップ
アプリケーションの構築レンダリング部分的なプリレンダリング

部分的なプリレンダリング

注意: 部分的なプリレンダリングは、canary版でのみ利用可能な実験的な機能であり、変更される可能性があります。本番環境での使用には適していません。

部分的なプリレンダリング (PPR) を使用すると、静的コンポーネントと動的コンポーネントを同じルートで組み合わせて使用できます。

ビルド中に、Next.js はルートのできるだけ多くの部分をプリレンダリングします。着信リクエストからの読み取りなど、動的なコードが検出された場合、関連するコンポーネントをReact Suspense境界で囲むことができます。すると、Suspense境界のフォールバックがプリレンダリングされたHTMLに含まれます。

Partially Prerendered Product Page showing static nav and product information, and dynamic cart and recommended products

🎥 視聴: PPR の理由と仕組み → YouTube (10分)

背景

PPR を使用すると、Next.js サーバーはプリレンダリングされたコンテンツを即座に送信できます。

クライアントからサーバーへのウォーターフォールを防ぐため、動的コンポーネントは初期のプリレンダリングを配信しながら、サーバーから並行してストリーミングを開始します。これにより、クライアントのJavaScriptがブラウザにロードされる前に、動的コンポーネントのレンダリングが開始されることが保証されます。

各動的コンポーネントに対して多くの HTTP リクエストが作成されるのを防ぐため、PPR は静的なプリレンダリングと動的コンポーネントを単一の HTTP リクエストに結合できます。これにより、各動的コンポーネントに複数のネットワークラウンドトリップが不要になります。

部分的なプリレンダリングの使用

段階的な導入 (バージョン 15 Canary バージョン)

Next.js 15 Canary バージョンでは、PPR が実験的な機能として利用可能です。安定版ではまだ利用できません。インストールするには

npm install next@canary

レイアウトページで部分的なプリレンダリングを段階的に導入するには、next.config.jsppr オプションを incremental に設定し、ファイルの先頭で experimental_ppr ルート設定オプションをエクスポートします。

next.config.ts
import type { NextConfig } from 'next'
 
const nextConfig: NextConfig = {
  experimental: {
    ppr: 'incremental',
  },
}
 
export default nextConfig
app/page.tsx
import { Suspense } from 'react'
import { StaticComponent, DynamicComponent, Fallback } from '@/app/ui'
 
export const experimental_ppr = true
 
export default function Page() {
  return (
    <>
      <StaticComponent />
      <Suspense fallback={<Fallback />}>
        <DynamicComponent />
      </Suspense>
    </>
  )
}

ご存知ですか:

  • experimental_pprを持たないルートはデフォルトでfalseとなり、PPRを使用してプリレンダリングされません。各ルートで明示的にPPRをオプトインする必要があります。
  • experimental_ppr は、ネストされたレイアウトやページを含む、ルートセグメントのすべての子に適用されます。すべてのファイルに追加する必要はなく、ルートの最上位セグメントにのみ追加してください。
  • 子セグメントで PPR を無効にするには、子セグメントで experimental_pprfalse に設定します。

ダイナミックコンポーネント

next build中にルートのプリレンダリングを作成する際、Next.jsではダイナミックAPIがReact Suspenseでラップされている必要があります。fallbackはその後にプリレンダリングに含まれます。

たとえば、cookiesheadersなどの関数を使用する場合

app/user.tsx
import { cookies } from 'next/headers'
 
export async function User() {
  const session = (await cookies()).get('session')?.value
  return '...'
}

このコンポーネントは、着信リクエストを見てクッキーを読み取る必要があります。これをPPRで使用するには、コンポーネントをSuspenseでラップする必要があります。

app/page.tsx
import { Suspense } from 'react'
import { User, AvatarSkeleton } from './user'
 
export const experimental_ppr = true
 
export default function Page() {
  return (
    <section>
      <h1>This will be prerendered</h1>
      <Suspense fallback={<AvatarSkeleton />}>
        <User />
      </Suspense>
    </section>
  )
}

コンポーネントは、値がアクセスされたときにのみ動的レンダリングにオプトインします。

例えば、pageからsearchParamsを読み取る場合、この値を別のコンポーネントにpropsとして転送できます。

app/page.tsx
import { Table } from './table'
 
export default function Page({
  searchParams,
}: {
  searchParams: Promise<{ sort: string }>
}) {
  return (
    <section>
      <h1>This will be prerendered</h1>
      <Table searchParams={searchParams} />
    </section>
  )
}

テーブルコンポーネント内で、searchParamsから値にアクセスすると、コンポーネントは動的に実行されます。

app/table.tsx
export async function Table({
  searchParams,
}: {
  searchParams: Promise<{ sort: string }>
}) {
  const sort = (await searchParams).sort === 'true'
  return '...'
}