😸

【イラスト付き】Next.jsの通信とRSA【要点一気読み】

2024/09/05に公開

はじめに

皆さんこんにちは。
今回はNext.jsの通信周りの基本的な書き方についてご紹介します。

Next.jsは通信に関して独自の機能を用意しています。またWebAPI作成も簡単に行うことができます。

こんな人にオススメ

  • Next.jsの通信周りの書き方の基本について理解したい
  • ブラウザAPIのfetchを使ったことがある

初めて学習する方にも分かるように、丁寧に解説していきます。
すでに利用している方も、是非一度目を通していただけると嬉しいです。

😋 Next.jsの通信周りのコードの雰囲気を捉えられるようにご紹介します♪

通信とWebAPI

まずポイントをチェック

  • Next.jsが拡張したfetch関数を利用して通信
    • データはキャッシュされる
  • appフォルダ以下のroute.tsxでWebAPIを作成可能

通信

Next.jsはブラウザのFetch APIを拡張した通信機能を用意しています。使い方はそのままにキャッシュを利用するようになっています。

取得したデータはキャッシュされるため、fetchを実行してもキャッシュが存在する場合はリクエストは行われずキャッシュが利用されます。

キャッシュが利用されるため、データが必要なコンポーネント自身でfetchをすることが推奨されています。これにより不要なpropsの受け渡しやデータの共有がなくなります。

fetchの第二引数の値にて、キャッシュの管理方法を指定することができます。

キャッシュする設定はデフォルトの動作です。

const res = await fetch('http://localhost:3000/api/items');  

キャッシュしない設定も可能です。その場合はno-storeを指定します。

const res = await fetch('http://localhost:3000/api/items', { cache: 'no-store'});

キャッシュの有効期間を指定し再取得する場合はrevalidateにキャッシュの有効期間を秒で指定します。0秒はキャッシュしないことと同義です。

const res = await fetch('http://localhost:3000/api/items', { next: { revalidate: 1 }, });

任意のタイミングでキャッシュを更新するにはタグを指定し、revalidateTag(‘タグ名’);を実行します。

const res = await fetch('http://localhost:3000/api/items', { next: { tags: ['tagName'] } });

WebAPI

ルートハンドラーを利用することで簡単にWebAPIを作成できます。

ルートハンドラーを作成するにはappフォルダ以下にroute.tsxを配置します。フォルダの階層がそのままURLに対応します。フォルダ名が[パラメータ名]の場合は、パスパラメータになります。

src
├── api
│   └── items
│       ├── [id]
│       │   └── route.tsx  ←/api/items/[id] に対応
│       └── route.tsx    ← /api/items に対応
├── layout.tsx
└── page.tsx

route.tsx内にリクエストメソッドに対応した名前の関数を作成し、エクスポートするだけで定義できます。リクエストとレスポンスのオブジェクトはそれぞれ、NextRequestとNextResponseを使います。

06.fetch-web/src/app/api/items/route.tsx(/api/itemsのGETのルートハンドラー抜粋)
export async function GET(request: NextRequest) {
    console.log('get');
    return NextResponse.json(items);
}

こちらのPOSTのルートハンドラーではrevalidateTag(タグ名);を実行しています。これはfetchのキャッシュを削除し再取得するための記述です。fetch実行時にタグを指定したキャッシュの更新ができるように設定した場合、そのタグ名を指定します。

06.fetch-web/src/app/api/items/route.tsx(/api/itemsのPOSTのルートハンドラー抜粋)
export async function POST(request: NextRequest) {
    const item = await request.json();
    items.push({ id: items.length + 1, name: item.name });

    // fetch('http://localhost:3000/api/items', { next: { tags: ['tagName'] } }); のキャッシュを再取得
    revalidateTag('tagName');
    return NextResponse.json({ item });
}

😋 簡単な記述でfetchやルートハンドラーを利用できます♪

参考リンク集

https://nextjs.org/docs/app/building-your-application/routing/route-handlers
https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#sharing-data-between-components
https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#fetching-data-on-the-server-with-fetch
https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#caching-data
https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#revalidating-data
https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#opting-out-of-data-caching
https://nextjs.org/docs/app/building-your-application/data-fetching/patterns#fetching-data-where-its-needed
https://nextjs.org/docs/app/building-your-application/caching#request-memoization
https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating
https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#sharing-data-between-components
https://nextjs.org/docs/app/api-reference/functions/fetch
https://nextjs.org/docs/app/building-your-application/caching#request-memoization
https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating
https://nextjs.org/docs/app/building-your-application/data-fetching#automatic-fetch-request-deduping
https://nextjs.org/docs/app/building-your-application/data-fetching/patterns
https://nextjs.org/learn/dashboard-app/fetching-data
https://nextjs.org/docs/app/building-your-application/routing/route-handlers
https://nextjs.org/docs/app/api-reference/file-conventions/route

React Server Actions

まずポイントをチェック

  • WebAPIを自作せず、フォーム送信時の処理が行える
  • Server Actionsは裏でPOSTのエンドポイントを作成する

React Sever Actionsは「フォーム送信時のサーバーサイドの処理」を用意し実行する機能です。POSTリクエストに対応するAPIエンドポイントが裏側で作成されるため、自分で作る必要はありません。

サーバーコンポーネントで利用する場合は、同一ファイル内にServer Actionsで利用する関数を定義することができます。関数はasync関数として定義し、処理の先頭に’use server’を記述します。

引数にはフォームに関する情報を持つオブジェクトを受け取ります。get(フォームのname属性の値) で入力欄の値を取得することができます。

07.server-action/src/app/form-data-sample/page.tsx(Server Actionsの非同期関数を抜粋)
const formAction = async (formData: FormData) => {
    'use server';
    console.log(formData.get('title'));
    console.log(formData.get('price'));
};

フォームと紐付けるにはformのaction属性に関数を指定します。input要素のname属性はServer Actionsの関数内でデータを取得する際に利用します。

07.server-action/src/app/form-data-sample/page.tsx(コンポーネントを抜粋)
export default function FormDataSample() {
    return (
        <div>
            <h2>form-data-sample</h2>
            <form action={formAction}>
                <input name="title" placeholder="title"/>
                <input name="price" placeholder="price"/>
                <button>送信</button>
            </form>
        </div>
    );
}

Server Actionsで利用する関数は別のファイルに定義することもできます。ファイルの先頭に’use server’を記述し、async関数をエクスポートします。

Server ActionsではReactが用意するuseFormStateフックを利用して状態を扱うことができます。これはフォームの処理に応じてstateを変更することができる機能です。Server Actionsの関数の引数では変更前のstateを受け取るとができます。

07.server-action/src/lib/actions.ts
'use server';

export async function plusData(previousState: number, formData: FormData) {
    console.log(previousState);
    return previousState + 1;
}

useFormStateはフックなのでクライアントコンポーネントで利用します。なおクライアントコンポーネントの場合、同じファイル内にServer Actionsの関数を定義できないため、別ファイルで定義したものをインポートして利用します。

useFormStateの引数はServer Actionsの関数とstateの初期値です。

07.server-action/src/app/form-state-sample/page.tsx
'use client';

import { plusData } from "@/lib/actions";
import { useFormState } from "react-dom";

export default function FormStateSample() {
  const [state, formAction] = useFormState(plusData, 0);
  return (
    <div>
      <h2>form-state-sample</h2>
      <form action={formAction}>
        {state}
        <button></button>
      </form>
    </div>
  );
}

😋 POSTのエンドポイントを用意しなくてもフォームの処理ができます♪

参考リンク集

おわりに

皆さん、お疲れ様でした。
ここまでご覧いただき、ありがとうございました。

Next.jsの基本的な書き方について確認をしていただきました。
Reactの書き方を基本としつつフォルダ構成やファイル名のルールなど独自のルールがあります。

😋 これからもプログラミング学習頑張りましょう♪

サンプルコード

Discussion