メインコンテンツまでスキップ

データを変更する方法

Next.jsでは、ReactのServer Functionsを使用してデータを変更できます。このページでは、Server Functionsを作成し、呼び出す方法について説明します。

Server Functionsの作成

Server Functionは、use serverディレクティブを使用して定義できます。このディレクティブを非同期関数の先頭に置くことで、その関数をServer Functionとしてマークするか、別のファイルの先頭に置いてそのファイルのすべてのエクスポートをマークできます。ほとんどの場合、別のファイルを使用することをお勧めします。

app/lib/actions.ts
'use server'

export async function createPost(formData: FormData) {}

export async function deletePost(formData: FormData) {}

Server Components

Server Functionsは、関数本体の先頭に"use server"ディレクティブを追加することで、Server Componentsにインライン化できます。

app/page.tsx
export default function Page() {
// Server Action
async function createPost() {
'use server'
// データを変更
// ...

return <></>
}

Client Components

Client ComponentsでServer Functionsを定義することはできません。ただし、"use server"ディレクティブが先頭にあるファイルからインポートすることで、Client Componentsで呼び出すことができます。

app/actions.ts
'use server'

export async function createPost() {}
app/ui/button.tsx
'use client'

import { createPost } from '@/app/actions'

export function Button() {
return <button formAction={createPost}>Create</button>
}

Server Functionsの呼び出し

Server Functionを呼び出す主な方法は2つあります。

  1. ServerおよびClient Componentsでのフォーム
  2. Client Componentsでのイベントハンドラ

フォーム

ReactはHTMLの<form>要素を拡張して、Server FunctionをHTMLのactionプロップで呼び出せるようにします。

フォームで呼び出されると、関数は自動的にFormDataオブジェクトを受け取ります。ネイティブのFormDataメソッドを使用してデータを抽出できます。

app/ui/form.tsx
import { createPost } from '@/app/actions'

export function Form() {
return (
<form action={createPost}>
<input type="text" name="title" />
<input type="text" name="content" />
<button type="submit">Create</button>
</form>
)
}
app/actions.ts
'use server'

export async function createPost(formData: FormData) {
const title = formData.get('title')
const content = formData.get('content')

// データを変更
// キャッシュを再検証
}

Good to know: actionプロップに渡されると、Server FunctionsはServer Actionsとも呼ばれます。

イベントハンドラ

Client ComponentでonClickなどのイベントハンドラを使用してServer Functionを呼び出すことができます。

app/like-button.tsx
'use client'

import { incrementLike } from './actions'
import { useState } from 'react'

export default function LikeButton({ initialLikes }: { initialLikes: number }) {
const [likes, setLikes] = useState(initialLikes)

return (
<>
<p>Total Likes: {likes}</p>
<button
onClick={async () => {
const updatedLikes = await incrementLike()
setLikes(updatedLikes)
}}
>
Like
</button>
</>
)
}

保留状態の表示

Server Functionを実行中に、ReactのuseActionStateフックを使用してローディングインジケータを表示できます。このフックはpendingブール値を返します。

app/ui/button.tsx
'use client'

import { useActionState } from 'react'
import { createPost } from '@/app/actions'
import { LoadingSpinner } from '@/app/ui/loading-spinner'

export function Button() {
const [state, action, pending] = useActionState(createPost, false)

return (
<button onClick={async () => action()}>
{pending ? <LoadingSpinner /> : 'Create Post'}
</button>
)
}

キャッシュの再検証

変更を行った後、Server Function内でrevalidatePathまたはrevalidateTagを呼び出すことで、Next.jsのキャッシュを再検証し、更新されたデータを表示できます。

app/lib/actions.ts
'use server'

import { revalidatePath } from 'next/cache'

export async function createPost(formData: FormData) {
// データを変更
// ...

revalidatePath('/posts')
}
app/actions.js
'use server'

import { revalidatePath } from 'next/cache'

export async function createPost(formData) {
// データを変更
// ...
revalidatePath('/posts')
}

リダイレクト

変更を行った後、ユーザーを別のページにリダイレクトしたい場合があります。Server Function内でredirectを呼び出すことでこれを行うことができます。

app/lib/actions.ts
'use server'

import { redirect } from 'next/navigation'

export async function createPost(formData: FormData) {
// データを変更
// ...

redirect('/posts')
}
app/actions.js
'use server'

import { redirect } from 'next/navigation'

export async function createPost(formData) {
// データを変更
// ...

redirect('/posts')
}