サーバーアクションとミューテーション
サーバーアクションは、サーバー上で実行される非同期関数です。Next.jsアプリケーションでフォーム送信とデータ変更を処理するため、サーバーコンポーネントとクライアントコンポーネントで呼び出すことができます。
🎥 ウォッチ: サーバーアクションを使用したミューテーションについてさらに詳しく → YouTube (10分)。
規約
サーバーアクションは、React "use server"
ディレクティブで定義できます。async
関数の先頭にディレクティブを配置して関数をサーバーアクションとしてマークするか、ファイルの先頭に配置してそのファイルのすべてのエクスポートをサーバーアクションとしてマークできます。
サーバーコンポーネント
サーバーコンポーネントは、関数レベルまたはモジュールレベルの "use server"
ディレクティブを使用できます。サーバーアクションをインラインで定義するには、関数本文の先頭に "use server"
を追加します:
クライアントコンポーネント
クライアントコンポーネントでサーバーアクションを呼び出すには、新しいファイルを作成し、ファイルの先頭に "use server"
ディレクティブを追加します。ファイル内のすべてのエクスポートされた関数は、クライアントコンポーネントとサーバーコンポーネントの両方で再利用できるサーバーアクションとしてマークされます:
アクションをプロップとして渡す
サーバーアクションをクライアントコンポーネントにプロップとして渡すこともできます:
通常、Next.jsのTypeScriptプラグインは、一般的にシリアライズできない関数である updateItemAction
にフラグを立てます。
しかし、action
という名前のプロップや、Action
で終わるプロップは、サーバーアクションを受け取ると想定されます。
これは、TypeScriptプラグインが実際にサーバーアクションか通常の関数かを知らないヒューリスティックにすぎません。
ランタイムの型チェックにより、クライアントコンポーネントに誤って関数を渡すことはできません。
動作
- サーバーアクションは
<form>
要素のaction
属性を使用して呼び出すことができます:- サーバーコンポーネントは、デフォルトでプログレッシブ・エンハンスメントをサポートし、JavaScriptが読み込まれていないか無効になっている場合でもフォームが送信されます。
- クライアントコンポーネントでは、サーバーアクションを呼び出すフォームは、JavaScriptがまだ読み込まれていない場合、クライアントハイドレーションを優先して送信をキューに入れます。
- ハイドレーション後、ブラウザはフォーム送信時にリフレッシュしません。
- サーバーアクションは
<form>
に限定されず、イベントハンドラ、useEffect
、サードパーティライブラリ、<button>
などの他のフォーム要素から呼び出すことができます。 - サーバーアクションは、Next.jsのキャッシュと再検証アーキテクチャと統合されます。アクションが呼び出されると、Next.jsは1回のサーバーラウンドトリップで更新されたUIと新しいデータの両方を返すことができます。
- 裏側では、アクションは
POST
メソッドを使用し、このHTTPメソッドのみがそれらを呼び出すことができます。 - サーバーアクションの引数と戻り値は、Reactによってシリアライズ可能である必要があります。シリアライズ可能な引数と値のリストについては、Reactのドキュメントを参照してください。
- サーバーアクションは関数です。つまり、アプリケーション内のどこでも再利用できます。
- サーバーアクションは、使用されているページまたはレイアウトのランタイムを継承します。
- サーバーアクションは、使用されているページまたはレイアウトのルートセグメント設定を継承し、
maxDuration
などのフィールドが含まれます。
例
フォーム
ReactはHTML <form>
要素を拡張し、action
プロップを使用してサーバーアクションを呼び出すことができます。
フォームで呼び出された場合、アクションは自動的に FormData
オブジェクトを受け取ります。React useState
を使用してフィールドを管理する必要はなく、代わりにネイティブの FormData
メソッドを使用してデータを抽出できます:
補足:
- 例: 読み込み中とエラー状態のフォーム
- 多くのフィールドを持つフォームを操作する場合、JavaScriptの
Object.fromEntries()
と共にentries()
メソッドの使用を検討することをお勧めします。例:const rawFormData = Object.fromEntries(formData)
。注意点として、formData
には追加の$ACTION_
プロパティが含まれます。- 詳細については、React
<form>
ドキュメントを参照してください。
追加の引数を渡す
JavaScriptの bind
メソッドを使用して、サーバーアクションに追加の引数を渡すことができます。
サーバーアクションは、フォームデータに加えて、userId
引数を受け取ります:
補足:
- 代替案として、フォーム内の非表示の入力フィールドとして引数を渡す方法があります(例:
<input type="hidden" name="userId" value={userId} />
)。ただし、値はレンダリングされたHTMLの一部となり、エンコードされません。.bind
はサーバーコンポーネントとクライアントコンポーネントの両方で動作します。また、プログレッシブ・エンハンスメントもサポートしています。
ネストされたフォーム要素
<form>
内の<button>
、<input type="submit">
、<input type="image">
などのネストされた要素内でサーバーアクションを呼び出すこともできます。これらの要素はformAction
プロップまたはイベントハンドラを受け入れます。
これは、フォーム内で複数のサーバーアクションを呼び出したい場合に便利です。例えば、投稿を公開することに加えて、下書きを保存するための特定の<button>
要素を作成できます。詳細については、Reactの<form>
ドキュメントを参照してください。
プログラムによるフォーム送信
requestSubmit()
メソッドを使用して、プログラムによりフォーム送信をトリガーできます。例えば、ユーザーが⌘
+ Enter
キーボードショートカットでフォームを送信する場合、onKeyDown
イベントをリスンできます:
これにより、最も近い<form>
の祖先の送信がトリガーされ、サーバーアクションが呼び出されます。
サーバー側のフォーム検証
required
やtype="email"
などのHTML属性を使用して、基本的なクライアント側のフォーム検証を行えます。
より高度なサーバー側の検証については、zodのようなライブラリを使用して、データを変更する前にフォームフィールドを検証できます:
フィールドがサーバー上で検証されたら、アクション内でシリアライズ可能なオブジェクトを返し、React useFormState
フックを使用してユーザーにメッセージを表示できます。
- アクションを
useFormState
に渡すことで、アクション関数のシグネチャが変更され、最初の引数として新しいprevState
またはinitialState
パラメータを受け取るようになります。 useFormState
はReactのフックであるため、クライアントコンポーネント内で使用する必要があります。
次に、アクションをuseFormState
フックに渡し、返されたstate
を使用してエラーメッセージを表示できます。
補足:
- これらの例では、Next.jsのApp RouterにバンドルされているReactの
useFormState
フックを使用しています。React 19を使用している場合は、代わりにuseActionState
を使用してください。詳細については、Reactのドキュメントを参照してください。
保留状態
- データを変更する前に、常にユーザーがアクションを実行する権限があることを確認する必要があります。認証と認可を参照してください。
useFormStatus
フックは、アクションの実行中にローディングインジケータを表示するために使用できるpending
ブール値を公開します。
補足:
- React 19では、
useFormStatus
は返されるオブジェクトに追加のキー(data、method、actionなど)が含まれます。React 19を使用していない場合、pending
キーのみが利用可能です。- React 19では、
useActionState
も返される状態にpending
キーが含まれます。
楽観的な更新
React useOptimistic
フックを使用して、サーバーアクションの完了を待たずに、UIを楽観的に更新できます:
イベントハンドラ
Server Actionsは通常<form>
要素内で使用されますが、onClick
などのイベントハンドラからも呼び出すことができます。例えば、いいねのカウントを増やす場合:
また、フォーム要素にイベントハンドラを追加することもできます。例えば、フォームフィールドのonChange
時にドラフトを保存する場合:
このようなケースでは、短時間に複数のイベントが発生する可能性があるため、不必要なServer Actionの呼び出しを防ぐためにデバウンスを推奨します。
useEffect
ReactのuseEffect
フックを使用して、コンポーネントのマウント時や依存関係の変更時にServer Actionを呼び出すことができます。これは、グローバルイベントに依存する、または自動的にトリガーする必要がある変更に便利です。例えば、アプリのショートカット用のonKeyDown
、無限スクロール用の交差オブザーバーフック、またはビュー数を更新するためのコンポーネントマウント時などです:
useEffect
の動作と注意点を必ず考慮してください。
エラー処理
エラーがスローされると、クライアント側の最も近いerror.js
または<Suspense>
境界でキャッチされます。UIで処理できるようにエラーを返すには、try/catch
を使用することをお勧めします。
例えば、Server Actionで新しいアイテムの作成時のエラーをメッセージで処理できます:
補足:
- エラーをスローする以外に、
useFormState
で処理できるオブジェクトを返すこともできます。サーバーサイドのバリデーションとエラー処理を参照してください。
データの再検証
Server Actions内でrevalidatePath
APIを使用して、Next.jsのキャッシュを再検証できます:
または、revalidateTag
を使用してキャッシュタグで特定のデータフェッチを無効化できます:
リダイレクト
Server Action完了後にユーザーを別のルートにリダイレクトする場合は、redirect
APIを使用できます。redirect
はtry/catch
ブロックの外で呼び出す必要があります:
Cookies
Server Action内でcookies
APIを使用してCookieをget
、set
、delete
できます:
Server ActionsからCookieを削除する追加の例を参照してください。
セキュリティ
デフォルトでは、Server Actionの作成とエクスポート時に、公開HTTPエンドポイントが作成され、同じセキュリティの前提条件と認証チェックを受けます。つまり、Server Actionまたはユーティリティ関数がコード内の他の場所でインポートされていなくても、依然として公開アクセス可能です。
セキュリティを向上させるために、Next.jsには以下の組み込み機能があります:
- セキュアなアクションID: Next.jsは、クライアントがServer Actionを参照および呼び出すための、暗号化された非決定的なIDを作成します。これらのIDはビルド間で定期的に再計算され、セキュリティが強化されます。
- デッドコード除去: 未使用のServer Actions(そのIDによって参照される)はクライアントバンドルから削除され、サードパーティによる公開アクセスを防ぎます。
補足:
IDは、コンパイル時に作成され、最大14日間キャッシュされます。新しいビルドが開始されるか、ビルドキャッシュが無効化されると、再生成されます。 このセキュリティ改善は、認証レイヤーが欠落している場合のリスクを軽減します。ただし、Server Actionは依然としてパブリックHTTPエンドポイントとして扱うべきです。
認証と承認
ユーザーがアクションを実行する権限があることを確認する必要があります。例:
クロージャと暗号化
コンポーネント内でServer Actionを定義すると、アクションが外側の関数のスコープにアクセスできるクロージャが作成されます。例えば、publish
アクションはpublishVersion
変数にアクセスできます:
クロージャは、レンダリング時のデータの「スナップショット」(例:publishVersion
)をキャプチャし、後でアクションが呼び出されたときに使用する必要がある場合に便利です。
ただし、これを行うには、キャプチャされた変数がクライアントに送信され、アクションが呼び出されたときにサーバーに戻されます。機密データがクライアントに公開されるのを防ぐため、Next.jsは自動的にクロージャ変数を暗号化します。新しい秘密鍵は、Next.jsアプリケーションがビルドされるたびに、各アクションに対して生成されます。これは、アクションが特定のビルドに対してのみ呼び出すことができることを意味します。
補足: 機密値がクライアントに公開されるのを防ぐために暗号化だけに頼ることはお勧めしません。代わりに、Reactタイント APIを使用して、特定のデータがクライアントに送信されるのを積極的に防ぐ必要があります。
暗号化キーの上書き(高度)
Next.jsアプリケーションを複数のサーバーでセルフホストする場合、各サーバーインスタンスが異なる暗号化キーを持つ可能性があり、潜在的な不整合が生じる可能性があります。
これを緩和するために、process.env.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY
環境変数を使用して暗号化キーを上書きできます。この変数を指定すると、暗号化キーがビルド間で永続的になり、すべてのサーバーインスタンスが同じキーを使用するようになります。
これは、複数のデプロイメント間で一貫した暗号化動作が重要なアプリケーションの高度なユースケースです。キーのローテーションや署名などの標準的なセキュリティ慣行を検討する必要があります。
補足: VercelにデプロイされたNext.jsアプリケーションは、これを自動的に処理します。
許可されたオリジン(高度)
Server Actionは<form>
要素で呼び出すことができるため、CSRFアタックに対して脆弱になります。
バックグラウンドでは、Server ActionはPOSTメソッドを使用し、このHTTPメソッドのみが呼び出しを許可されます。これにより、最新のブラウザで、特にSameSiteクッキーがデフォルトであることで、ほとんどのCSRF脆弱性を防ぎます。
追加の保護として、Next.jsのServer ActionはOriginヘッダーをHostヘッダー(またはX-Forwarded-Host
)と比較します。一致しない場合、リクエストは中止されます。つまり、Server Actionは、それをホストするページと同じホストでのみ呼び出すことができます。
リバースプロキシや多層バックエンドアーキテクチャ(サーバーAPIが本番ドメインと異なる)を使用する大規模なアプリケーションの場合、serverActions.allowedOrigins
設定オプションを使用して、安全なオリジンのリストを指定することをお勧めします。このオプションは文字列の配列を受け入れます。
Server ActionsのセキュリティとServer Actionsの詳細をご覧ください。
その他のリソース
詳細については、以下のReactドキュメントをご確認ください: