春日部つむぎ「Partial Prerendering (PPR) って何ですか？」

:::note warn
この記事は`Gemini-exp-1114`で生成した内容をベースに使用しています。
:::

---


## 1. はじめに：Partial Prerendering (PPR) とは？

ずんだもん「こんにちは！僕ずんだもんなのだ！今日はつむぎちゃんと一緒に、Next.js の新機能 **Partial Prerendering (PPR)** について徹底解説するのだ！」

つむぎ「春日部つむぎです！ずんだもんさん、よろしくお願いします！PPR、名前は聞いたことあるけど、よく分かってないんです…」

ずんだもん「つむぎちゃん、安心してなのだ！PPR は **Partial Prerendering** の略で、日本語だと **部分的な事前レンダリング** という意味なのだ！簡単に言うと、ページの **一部を事前に静的に生成** しておいて、**残りの部分をリクエスト時に動的に生成** する技術なのだ！」

つむぎ「部分的な事前レンダリング…？なんだか難しそうですね…」

ずんだもん「大丈夫なのだ！これからじっくり説明していくから、安心してほしいのだ！PPR を使うことで、**初期表示の高速化** と **動的なコンテンツの柔軟性** を両立できるのが最大のメリットなのだ！」

## 2. PPR の仕組み：Suspense を活用した魔法

ずんだもん「PPR がどうやって動いているか説明するのだ！PPR は React の **Suspense** という機能を活用しているのだ！Suspense は非同期処理のローディング状態を管理するための機能なのだ！」

つむぎ「Suspense…？聞いたことあるけど、よく分かってないです…」

ずんだもん「大丈夫なのだ！具体例を見ながら説明するのだ！」

### コード例で見る PPR の実装

```jsx
// app/page.js
import { Suspense } from 'react';
import DynamicContent from './DynamicContent';

export default function Page() {
  return (
    <div>
      <h1>Welcome to My Blog!</h1> 
      <Suspense fallback={<div>Loading...</div>}>
        <DynamicContent />
      </Suspense>
      <p>Copyright 2024 My Blog</p>
    </div>
  );
}
```
```jsx
// app/DynamicContent.js
async function fetchData() {
  // 記事データを取得する非同期処理
  await new Promise((resolve) => setTimeout(resolve, 2000)); // 2秒待機
  return { title: 'PPR Explained!', content: 'PPR is awesome!' };
}

export default async function DynamicContent() {
  const data = await fetchData();
  return (
    <div>
      <h2>{data.title}</h2>
      <p>{data.content}</p>
    </div>
  );
}
```

ずんだもん「このコードでは、`DynamicContent` コンポーネントが記事データを取得する間、`Loading...` と表示されるのだ！そして、データが取得できたら、記事のタイトルと内容が表示されるのだ！」

つむぎ「`Suspense` で `DynamicContent` を囲んで、`fallback` でローディング中の表示を指定してるんですね！」

ずんだもん「ご明察なのだ！一方、`<h1>Welcome to My Blog!</h1>` と `<p>Copyright 2024 My Blog</p>` は事前に静的に生成されるから、すぐに表示されるのだ！これが **部分的な事前レンダリング** なのだ！」

## 3. PPR のメリット：ユーザー体験を劇的に向上！

つむぎ「なるほど！PPR を使うとどんな良いことがあるんですか？」

ずんだもん「PPR には大きく分けて2つのメリットがあるのだ！」

### 初期表示速度の改善

ずんだもん「まず、**初期表示速度が大幅に改善される** のだ！ページの全てが読み込まれるのを待つ必要がなく、先に表示できる部分を素早く表示できるから、ユーザーは待たされるストレスを感じにくいのだ！」

つむぎ「確かに、読み込みが遅いとイライラしちゃいますよね…」

### 動的コンテンツとの柔軟な連携

ずんだもん「そして、**動的なコンテンツとの連携が柔軟になる** のだ！必要な部分だけを動的に読み込むことで、ページの表示を遅らせることなく、最新の情報やユーザーに合わせたコンテンツを提供できるのだ！」

つむぎ「なるほど！ユーザー体験が向上するんですね！」

## 4. PPR 導入の注意点：設計とUIが鍵を握る

ずんだもん「ただし、PPR を効果的に使うためには注意点もあるのだ！」

### 動的/静的コンテンツの適切な切り分け

ずんだもん「まず、**動的に読み込む部分と静的に生成する部分を適切に切り分ける必要** があるのだ！ユーザーが最初に見る可能性が高いコンテンツは静的に生成しておくべきなのだ！」

つむぎ「確かに、最初に表示される部分が遅いと意味ないですもんね…」

### 魅力的なローディング表示

ずんだもん「そして、**ローディング中の表示も重要** なのだ！ただ `Loading...` と表示するだけではなく、スケルトンスクリーンやプログレスバーを使うなど、ユーザーにストレスを与えないような工夫が必要なのだ！」

つむぎ「ローディング中もおしゃれにすることで、ユーザーを飽きさせないってことですね！」

## 5. 実践！PPR を活用したサンプルコード

ずんだもん「もっと具体的な例を見たいという声が聞こえてきたのだ！そこで、PPR を活用したサンプルコードを紹介するのだ！」

**サンプルコード：商品一覧ページ**
今回は、商品一覧ページを例に、PPR を使ってどのように実装するか見ていくのだ！このページでは、ページ上部のカテゴリーリストは静的に生成し、商品リストは動的に読み込むようにするのだ！
```js
// app/products/page.js
import { Suspense } from 'react';
import ProductList from './ProductList';
import CategoryList from './CategoryList';

export default function ProductsPage() {
  return (
    <div>
      <header>
        <h1>商品一覧</h1>
        <CategoryList /> 
      </header>
      <main>
        <Suspense fallback={<div>Loading Products...</div>}>
          <ProductList />
        </Suspense>
      </main>
      <footer>
        <p>Copyright 2024 My Shop</p>
      </footer>
    </div>
  );
}
```
```js
// app/products/CategoryList.js
export default function CategoryList() {
  // カテゴリーリストを静的に生成する（実際はAPIから取得するなど）
  const categories = ['Electronics', 'Clothing', 'Books'];

  return (
    <ul>
      {categories.map(category => (
        <li key={category}>{category}</li>
      ))}
    </ul>
  );
}
```
```js
// app/products/ProductList.js
async function fetchProducts() {
  // 商品データを取得する非同期処理（実際はAPIから取得するなど）
  await new Promise((resolve) => setTimeout(resolve, 2000)); // 2秒待機
  return [
    { id: 1, name: 'Product A', price: 100 },
    { id: 2, name: 'Product B', price: 200 },
    { id: 3, name: 'Product C', price: 300 },
  ];
}

export default async function ProductList() {
  const products = await fetchProducts();

  return (
    <ul>
      {products.map(product => (
        <li key={product.id}>
          {product.name} - ${product.price}
        </li>
      ))}
    </ul>
  );
}
```
**コードの解説**
ずんだもん「`ProductsPage` コンポーネントでは、`CategoryList` をヘッダー内に配置して、静的に生成しているのだ！一方、`ProductList` は `Suspense` で囲んで、動的に読み込むようにしているのだ！」

つむぎ「`ProductList` が読み込まれる間は `Loading Products...` と表示されるんですね！」

ずんだもん「そういうことなのだ！ユーザーはヘッダーのカテゴリーリストをすぐに確認できるから、待たされている感じが軽減されるのだ！」

つむぎ「なるほど！PPR を使うことで、ページの使い勝手が向上するんですね！」

ずんだもん「その通りなのだ！このように、PPR はページの特性に合わせて、効果的に活用することが重要になってくるのだ！」


## 6. まとめ：PPR を使いこなし、快適なWeb体験を提供しよう

ずんだもん「というわけで、今回は Next.js の新機能 **Partial Prerendering (PPR)** について解説したのだ！」

つむぎ「PPR を使えば、初期表示速度が向上して、ユーザー体験が向上するんですね！」

ずんだもん「その通りなのだ！ただし、**設計とUIデザインが重要** だということも忘れないでほしいのだ！」

つむぎ「分かりやすく説明してくれてありがとうございました！PPR、マスターできるように頑張ります！」

ずんだもん「僕も応援しているのだ！一緒に Next.js を極めるのだ！」

## 7. 参考文献

- [Next.js 公式ドキュメント](https://nextjs.org/docs)
- [React 公式ドキュメント](https://reactjs.org/docs/concurrent-mode-suspense.html)

---

私は普段、WEBサービスやモバイルアプリの自社開発・運営を行っております。
特にAI駆動の開発を採用して、個人規模で高品質かつ高速なプロダクト開発ができるように、日々活動をしています。

よろしければ[**Xアカウント**](https://x.com/dai_mori219)のフォローをお願い致します。