Next.js サーバーアクションの使用方法

Next.js の 13.4 リリースでは、安定した App ルーターとサーバーアクションによるデータの変更機能が追加されました。この機能は、サーバーコンポーネントから完全にデータの変更を実行できるため、ゲームチェンジャーです。これにより、速度、セキュリティ、アプリの全体的なパフォーマンスなどの分野で多くのメリットが得られます。

サーバーアクションとは何か、および Next.js アプリケーションでこの新機能を使用する方法を学びましょう。

サーバーアクションとは?

サーバーアクションを使用すると、サーバーコンポーネントのすぐ横にワンオフのサーバーサイド関数を記述できます。これは、GraphQL データの変更を含むフォームを送信したり、その他の種類のデータの変更を行ったりする際に API ルートを記述する必要がなくなったため、大きな意味を持ちます。

サーバーで実行される関数を作成し、クライアントまたはサーバーコンポーネントから呼び出すことができます。これは Next.js 13.4 のアルファ機能であり、React Actions を基に構築されています。サーバーアクションを使用すると、クライアント側の JavaScript が削減され、段階的に強化されたフォームを作成するのに役立ちます。

サーバーアクションの例

サーバーアクションを使用すると、サーバー上の Next.js 内で変更を実行できます。投稿を作成するためのフォームをレンダリングする Next.js ページの例で、この新機能を見てみましょう。

インポートを次に示します。

import Link from "next/link"
import FormGroup from "@/components/FormGroup"
import { revalidateTag } from "next/cache"
import { redirect } from "next/navigation"

次に、投稿を作成するためのコードを示します。この関数はサーバーアクションです。サーバーで実行され、投稿のタイトルと本文を API に送信します (API はデータベースに投稿を作成します)。

async function createPost(data) {
"use server"
const title = data.get("title")
const body = data.get("body")

await fetch("http://127.0.0.1/posts", {
header: {"Content-Type": "application/json"},
method: POST,
body: JSON.stringify({title, body})
})

revalidateTag("posts")
redirect("/")
}

この関数は、POST リクエストを介して/postsエンドポイントに送信される投稿のタイトルと本文を取得します。次に、キャッシュを強制的に更新して「posts」タグに関連付けられたコンテンツを更新し、ホームページにリダイレクトします。

新しい投稿のタイトルと本文を収集するためのフォームを次に示します。

export default NewPostForm() {
return (
<form action={createPost}>
<div>
<FormGroup>
<label htmlFor="title">Title</label>
<input type="text" name="title" />
</FormGroup>
</div>

<div>
<FormGroup>
<label htmlFor="title">Body</label>
<textarea type="text" name="body"> <textarea/>
</FormGroup>
</div>

<div>
<button> Save </button>
</div>
</form>
)
}

このフォームには、投稿の作成に関連するロジックは含まれておらず、フォームアクションcreatePost()関数のみが含まれていることがわかります。createPost 関数には「use server」ディレクティブがあり、その関数内のすべてがサーバーで実行されることを宣言していることを思い出してください。

すべてのコードはサーバーで実行されており、クライアントはそのことを何も知りません。これは、フォームがサーバーコンポーネントであり、クライアントで動的にレンダリングされるものが何もないためです。

保存ボタンをクリックすると、Next.js がcreatePost()関数を呼び出します。これにより、タイトルと本文がフォームデータとして送信され、ローカル API に投稿されて情報が保存されます。

投稿の再検証

createPost()関数の最後には、次のコード行があります。

revalidateTags("posts")

その関数が何をしているのかを理解するために、投稿ページがあると想像してください。投稿コンポーネント内で、getPosts()という名前の関数を呼び出して、データベースからすべての投稿を取得し、ユーザーに表示できるようにレンダリングします。

export default async function Posts(){
const posts = await getPosts()

return (
<div>
{posts.map(post => {
<PostCard key={post.id} {...post} />
})}
</div>
)
}

getPosts()関数は次のようになります。

async function getPosts() {
const res = await fetch("https://127.0.0.1/posts?sort=title", {
next: {tags: ["posts"], revalidate: 3600 }
})

return res.json()
}

この関数はnextオプションを fetch に渡して、再検証期間を設定できるようにします。既定では、サーバーコンポーネント内で作成するすべての fetch リクエストは永遠にキャッシュされます。キャッシュを追跡し、必要に応じて更新することは、Next.js のデータフェッチングの重要な部分です。

上記のコードは、Next.js にpostsデータを最大 1 時間 (3,600 秒) キャッシュするように指示しています。1 時間経過すると、データは古くなり、Next.js はそれを更新してデータベースから最新のデータを取得します。

createPost()関数は、残りの作業が完了したらrevalidateTag("posts")を呼び出すことを忘れないでください。これにより、Next.js は、アプリが作成した新しい投稿を含む可能性のあるそのデータを再フェッチすることを強制されます。

コードがサーバーで実行されていることの証明

すべてのコードがサーバーで実行されていることを確認するために、次の console log ステートメントをcreatePost()関数内に追加できます。

console.log("サーバーで実行中")

次に、送信ボタンをクリックして新しい投稿を作成してみます。コードがサーバーで実行されている場合、そのログメッセージがターミナルに表示されます。しかし、クライアントで実行されている場合は、ログがブラウザのコンソールに表示されます。

これにより、環境変数、データベース接続、パスワードなどの機密情報をサーバーに配置しても、クライアントに漏洩する心配なく安全になります。その後、Next.js アプリの .env ファイルから文字列を読み取ることができます。

特に本番環境では、Next.js の 13.4 以降のバージョンでサーバーアクションを使用することをお勧めします。しかし、より多くの機能をサーバーに移行することで、できることの限界を常に押し広げているため、この機能がどこまで進化するかを目にするのは本当にエキサイティングです。クライアントアプリの記述が容易になり、開発プロセスがはるかに楽しくなるはずです。

Next.js への移行について詳しく学ぶ

多くのフロントエンド開発者は、UI 開発に React を使用しています。しかし、サーバーサイドレンダリングや静的サイト生成などの機能のおかげで、多くの開発者がアプリを移行して Next.js を使用しています。この移行は非常に簡単です。Next.js の構文は React に非常に似ているためです。

追加のパフォーマンスとセキュリティの向上により、移行の必要性はさらに高まっています。サーバーサイドコンポーネントを利用できることと、新しく取り上げたサーバーアクションを組み合わせることで、Next.js は純粋な React と比較して、より安全でパフォーマンスの高い選択肢となっています。React 開発者として、アプリを Next.js に移行する方法を学ぶべきです。