Sponsor
ChatHubChatHub Use GPT-4, Gemini, Claude 3.5 and more chatbots side-by-side
ここをクリック
Menu

部分的プリレンダリング

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

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

ビルド時に、Next.jsはルートの可能な限りの部分をプリレンダリングします。動的なコード(受信リクエストからの読み取りなど)が検出された場合、関連するコンポーネントをReact Suspense境界でラップできます。Suspenseの代替表示用コンポーネントはプリレンダリングされたHTMLに含まれます。

部分的にプリレンダリングされた商品ページ。静的なナビゲーションと商品情報、動的なカートとおすすめ商品を表示

🎥 視聴する: 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
TypeScript
import type { NextConfig } from 'next'
 
const nextConfig: NextConfig = {
  experimental: {
    ppr: 'incremental',
  },
}
 
export default nextConfig
app/page.tsx
TypeScript
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
TypeScript
import { cookies } from 'next/headers'
 
export async function User() {
  const session = (await cookies()).get('session')?.value
  return '...'
}

このコンポーネントはクッキーを読み取るために受信リクエストを確認する必要があります。PPRで使用するには、コンポーネントをSuspenseでラップする必要があります:

app/page.tsx
TypeScript
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
TypeScript
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
TypeScript
export async function Table({
  searchParams,
}: {
  searchParams: Promise<{ sort: string }>
}) {
  const sort = (await searchParams).sort === 'true'
  return '...'
}