Menu

データの更新方法

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

サーバー関数の作成

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

app/lib/actions.ts
TypeScript
'use server'
 
export async function createPost(formData: FormData) {}
 
export async function deletePost(formData: FormData) {}

サーバーコンポーネント

サーバー関数は、関数本体の先頭に"use server"ディレクティブを追加することで、サーバーコンポーネント内にインライン化できます:

app/page.tsx
TypeScript
export default function Page() {
  // Server Action
  async function createPost() {
    'use server'
    // Update data
    // ...
 
  return <></>
}

クライアントコンポーネント

クライアントコンポーネント内でサーバー関数を定義することはできません。ただし、先頭に"use server"ディレクティブが記述されたファイルからインポートすることで、クライアントコンポーネント内でサーバー関数を呼び出すことができます:

app/actions.ts
TypeScript
'use server'
 
export async function createPost() {}
app/ui/button.tsx
TypeScript
'use client'
 
import { createPost } from '@/app/actions'
 
export function Button() {
  return <button formAction={createPost}>Create</button>
}

サーバー関数の呼び出し

サーバー関数を呼び出す主な方法は2つあります:

  1. サーバーコンポーネントとクライアントコンポーネントのフォーム
  2. クライアントコンポーネントのイベントハンドラ

フォーム

ReactはHTML <form>要素を拡張し、HTML actionプロパティでサーバー関数を呼び出すことができるようにしています。

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

app/ui/form.tsx
TypeScript
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
TypeScript
'use server'
 
export async function createPost(formData: FormData) {
  const title = formData.get('title')
  const content = formData.get('content')
 
  // Update data
  // Revalidate cache
}

補足: actionプロパティに渡されると、サーバー関数は_サーバーアクション_とも呼ばれます。

イベントハンドラ

クライアントコンポーネントでは、onClickなどのイベントハンドラを使用してサーバー関数を呼び出すことができます。

app/like-button.tsx
TypeScript
'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>
    </>
  )
}

処理中の状態を表示する

サーバー関数を実行している間、ReactのuseActionStateフックを使って読み込みインジケーターを表示できます。このフックはpendingブール値を返します:

app/ui/button.tsx
TypeScript
'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>
  )
}

キャッシュの再検証

更新を実行した後、サーバー関数内でrevalidatePathまたはrevalidateTagを呼び出すことで、Next.jsのキャッシュを再検証し、更新されたデータを表示できます:

app/lib/actions.ts
TypeScript
'use server'
 
import { revalidatePath } from 'next/cache'
 
export async function createPost(formData: FormData) {
  // Update data
  // ...
 
  revalidatePath('/posts')
}

リダイレクト

更新を実行した後、ユーザーを別のページにリダイレクトしたい場合があります。サーバー関数内でredirectを呼び出すことでこれを実現できます:

app/lib/actions.ts
TypeScript
'use server'
 
import { redirect } from 'next/navigation'
 
export async function createPost(formData: FormData) {
  // Update data
  // ...
 
  redirect('/posts')
}

API リファレンス

このページで紹介された機能について詳しく知るには、APIリファレンスをご覧ください。