Next.js 13.4 App Router のレンダリング実装方法

# はじめに
以下の記事では、Pages Router のレンダリング実装方法について記載しました。

https://qiita.com/Yasushi-Mo/items/4fd56259427d2a64cae7

今回は App Router のレンダリング実装方法について記載していきます。

# 開発環境
開発環境は以下の通りです。
- Windows11
- VSCode
- Next.js 13.4.7
- React 18.2.0
- TypeScript 5.1.3

# プロジェクト作成
まずは以下のコマンドを実行して、プロジェクトを作成します。

```
npx create-next-app@latest
```

インストール中にプロンプトが表示されます。No / Yes はすべてデフォルト値を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/e8afcd00-cd25-4d7a-ef32-c20400149ffc.png)

インストールが完了するとプロジェクトファイルが作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/2bb8ad36-f716-da18-6dbb-939ee0a8d12d.png)

# Client 側でのレンダリング
App Router では、Server Component と Client Component というようにコンポーネント単位でレンダリングの種類を選択できるようになりました。デフォルトでは、Server Component が利用されます。そのため、Client Component を利用するときは、```"use client"``` とファイルに記載する必要があります。

例えば、SWR を利用してクライアント側で、データを取得したい場合、以下のように記載します。

```src/app/client-side-rendering/page.tsx
"use client";

import { SAMPLE_API_ENDPOINT } from "@/api";
import { FetchedRandomJoke } from "@/components/FetchedRandomJoke";
import { RandomJoke } from "@/types";
import Head from "next/head";
import useSWR from "swr";
export const TITLE = "Client-Side Rendering (CSR)";

export default function ClientSideRendering() {
  const { data: randomJoke } = useSWR<RandomJoke>(SAMPLE_API_ENDPOINT, fetcher);

  return (
    <>
      <Head>
        <title>{TITLE}</title>
      </Head>
      <h1>{TITLE}</h1>
      <p>Data fetched on the client-side only.</p>
      <FetchedRandomJoke randomJoke={randomJoke} />
    </>
  );
}

async function fetcher() {
  const response = await fetch(SAMPLE_API_ENDPOINT);
  const randomJoke = await response.json();

  return randomJoke;
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/9e90c4c4-1e62-5663-f48e-62a681302d99.png)

:::note alert
```"use client"``` を記載しないと、以下のようにエラーになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/bd714302-f320-ebbe-116e-a221d3c4880f.png)

:::

# Dynamic Data Fetching
サーバー側でレンダリング（データ取得）する手法として、Dynamic Data Fetching と Static Data Fetching の2種類あります。
Dynamic Data Fetching を利用する場合、fetch の第二引数に ```await fetch(SAMPLE_API_ENDPOINT, { cache: "no-store" });``` を追加します。

```src/app/dynamic-data-fetching/page.tsx
import Head from "next/head";
import { RandomJoke } from "@/types";
import { SAMPLE_API_ENDPOINT } from "@/api";
import { FetchedRandomJoke } from "@/components/FetchedRandomJoke";

export const TITLE = "Dynamic Data Fetching";

export default async function DynamicDataFetching() {
  const randomJoke = await getRandomJoke();

  return (
    <>
      <Head>
        <title>{TITLE}</title>
      </Head>
      <h1>{TITLE}</h1>
      <p>
        Data fetched on the server-side at <b>each</b> request before sending to
        the client.
      </p>
      <FetchedRandomJoke randomJoke={randomJoke} />
    </>
  );
}

export async function getRandomJoke(): Promise<RandomJoke> {
  const response = await fetch(SAMPLE_API_ENDPOINT, { cache: "no-store" });
  const randomJoke = await response.json();

  return randomJoke;
}
```

# Static Data Fetching
Static Data Fetching を利用する場合、fetch の第二引数には何も加える必要はありません。

```src/app/dynamic-data-fetching/page.tsx
import Head from "next/head";
import { RandomJoke } from "@/types";
import { SAMPLE_API_ENDPOINT } from "@/api";
import { FetchedRandomJoke } from "@/components/FetchedRandomJoke";

export const TITLE = "Static Data Fetching";

export default async function StaticDataFetching() {
  const randomJoke = await getRandomJoke();

  return (
    <>
      <Head>
        <title>{TITLE}</title>
      </Head>
      <h1>{TITLE}</h1>
      <p>
        Data fetched at <b>build-time</b> on the server-side before sending to
        the client.
      </p>
      <FetchedRandomJoke randomJoke={randomJoke} />
    </>
  );
}

export async function getRandomJoke(): Promise<RandomJoke> {
  const response = await fetch(SAMPLE_API_ENDPOINT);
  const randomJoke = await response.json();

  return randomJoke;
}
```

:::note
fetch の第二引数を ```{ next: { revalidate: 10 } }``` のようにすると、データを再取得する間隔を指定することができます。
:::

# 参考
- [React Essentials](https://nextjs.org/docs/getting-started/react-essentials)
- [Data Fetching](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching)