Next.js(App Router)のServer Actionsを使って再検証処理まで実装してみる
Next.js(v13)のキャッチアップをしたので、その学習ログをまとめていきたいと思います。
今回は、サーバーアクションについて検証したので、少しでも参考になれば嬉しいです。
サーバーアクションとは?
概要
Server Actions は Next.js のバージョン 13.4 で新たに追加された機能です。
サーバーコンポーネント・クライアントコンポーネントの両方でサーバー上で実行される関数を呼び出すことが可能になり、これによってAPI エンドポイントを作成する必要がなくなりました。
サーバーアクションの有効化
next.config.js
でserverActionsをtrueに設定することで使用が可能になります。
module.exports = {
experimental: {
serverActions: true,
},
}
呼び出し
サーバーアクションは、サーバーコンポーネントとクライアントコンポーネントの両方から呼び出しが可能です。
🙆♂️ サーバーコンポーネントから呼び出す場合
export default function ServerComponent() {
async function myAction() {
'use server'
// ...
}
}
🙆♂️ クライアントコンポーネントから呼び出す場合
'use server'
export async function myAction() {
// ...
}
'use client'
import { myAction } from './actions'
export default function ClientComponent() {
return (
<form action={myAction}>
<button type="submit">Add to Cart</button>
</form>
)
}
🙅♂️ この場合はNGです。
'use client'
export default function ClientComponent() {
async function myAction() {
'use server'
// ...
}
return (
<form action={myAction}>
<button type="submit">Add to Cart</button>
</form>
)
}
サイズ制限
デフォルトで設定されてる最大サイズは1MB
であり、必要に応じてサイズの変更が可能です。
module.exports = {
experimental: {
serverActions: true,
serverActionsBodySizeLimit: '2mb',
},
}
サンプルコード
以下のコードは、簡易的な投稿ページの実装をしています。
ここでは概要については省略しますが、shadcn/ui(Tailwind CSS)を使ってスタイリングをしています。
全体コード
import { Button } from "@/feature/shadcn/ui/button"
import { Input } from "@/feature/shadcn/ui/input"
import { Label } from "@/feature/shadcn/ui/label"
import { Textarea } from "@/feature/shadcn/ui/textarea"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/feature/shadcn/ui/card"
import { revalidateTag } from "next/cache"
type PostProps = {
id: number
title: string
description: string
}
const Page = async () => {
const res = await fetch("http://localhost:3032/posts", {
method: "GET",
cache: "no-cache",
next: {
tags: ["posts"],
},
})
const posts: PostProps[] = await res.json()
const addPost = async (formData: FormData) => {
"use server"
const title = formData.get("title")
const description = formData.get("description")
const res = await fetch("http://localhost:3032/posts", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
title: title,
description: description,
}),
})
revalidateTag("posts")
}
return (
<div className="w-full">
<h1 className="text-[18px] font-bold mb-4">投稿ページ</h1>
{/* 投稿フォーム */}
<div className="w-[500px] mb-8">
<form action={addPost}>
<div className="flex flex-col gap-1 mb-4">
<Label>タイトル</Label>
<Input name="title" />
</div>
<div className="flex flex-col gap-1 mb-4">
<Label>説明文</Label>
<Textarea name="description" />
</div>
<div className="w-full justify-center items-center text-center">
<Button className="w-[200px]">投稿</Button>
</div>
</form>
</div>
{/* 投稿一覧 */}
<div className="flex flex-row flex-wrap gap-8">
{posts.map((post, index) => {
return (
<Card key={`post${index}`}>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">{post.title}</CardTitle>
</CardHeader>
<CardContent>
<div className="text-md font-bold">{post.description}</div>
</CardContent>
</Card>
)
})}
</div>
</div>
)
}
export default Page
再検証
再検証とは、データ キャッシュを消去し、最新のデータを再フェッチするプロセスです。
データが変更され、最新の情報を取得したい場合に使用します。
以下は参考記事です。
revalidateTag
を設定してあげることで、特定のキャッシュデータを更新することが可能になります。
const res = await fetch("http://localhost:3032/posts", {
...
next: {
tags: ["posts"],
},
})
const addPost = async (formData: FormData) => {
...
revalidateTag("posts")
}
感想
Next.jsの成長スピードが早すぎてキャッチアップするのが大変だけど、Next.jsオンリーでできる幅が増えてきるので、嬉しい点でもあります。
次のリリースは不明ですが、どんな機能が追加されるのか発表が楽しみです!
おまけ
弊社では、スマホやPC1つで完結する網羅的な教材と、無制限で解ける本番と同形式の模試で、短期間での資格取得を目指すことができる簿記のアプリ 『Funda簿記』 を運営しています。
少しでも興味のある方がいれば、リンクよりアクセスしていただくか、メールにてお願いします☺️
Discussion