サーバーアクション
このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →
Server Actions を使用すると、サーバー上で関数を定義し、フレームワークによってネットワーク層が抽象化された状態でクライアントコンポーネントから直接呼び出すことができます。
tRPC プロシージャを使用して Server Actions を定義することで、tRPC の組み込み機能をすべて利用できます。これには入力検証、ミドルウェアによる認証・認可、出力検証、データトランスフォーマーなどが含まれます。
Server Actions 統合は experimental_ プレフィックスを使用しており、現在も活発に開発中です。API は将来のリリースで変更される可能性があります。
Server Action プロシージャの設定
1. experimental_caller で基本プロシージャを定義
プロシージャビルダーで experimental_caller と experimental_nextAppDirCaller を使用し、プレーン関数(Server Actions)として呼び出せるプロシージャを作成します。pathExtractor オプションでメタデータによるプロシージャ識別が可能になり、Server Actions には user.byId のようなルーターパスがないため、ロギングやオブザーバビリティに有用です。
server/trpc.tstsimport {initTRPC ,TRPCError } from '@trpc/server';import {experimental_nextAppDirCaller } from '@trpc/server/adapters/next-app-dir';interfaceMeta {span : string;}export constt =initTRPC .meta <Meta >().create ();export constserverActionProcedure =t .procedure .experimental_caller (experimental_nextAppDirCaller ({pathExtractor : ({meta }) => (meta asMeta )?.span ?? '',}),);
server/trpc.tstsimport {initTRPC ,TRPCError } from '@trpc/server';import {experimental_nextAppDirCaller } from '@trpc/server/adapters/next-app-dir';interfaceMeta {span : string;}export constt =initTRPC .meta <Meta >().create ();export constserverActionProcedure =t .procedure .experimental_caller (experimental_nextAppDirCaller ({pathExtractor : ({meta }) => (meta asMeta )?.span ?? '',}),);
2. ミドルウェアでコンテキストを追加
Server Actions は HTTP アダプターを経由しないため、createContext でコンテキストを注入できません。代わりにミドルウェアを使用して、セッションデータなどのコンテキストを提供します:
server/trpc.tstsimport {initTRPC ,TRPCError } from '@trpc/server';import {experimental_nextAppDirCaller } from '@trpc/server/adapters/next-app-dir';import {currentUser } from '../auth';interfaceMeta {span : string;}export constt =initTRPC .meta <Meta >().create ();export constserverActionProcedure =t .procedure .experimental_caller (experimental_nextAppDirCaller ({pathExtractor : ({meta }) => (meta asMeta )?.span ?? '',}),).use (async (opts ) => {constuser = awaitcurrentUser ();returnopts .next ({ctx : {user } });});
server/trpc.tstsimport {initTRPC ,TRPCError } from '@trpc/server';import {experimental_nextAppDirCaller } from '@trpc/server/adapters/next-app-dir';import {currentUser } from '../auth';interfaceMeta {span : string;}export constt =initTRPC .meta <Meta >().create ();export constserverActionProcedure =t .procedure .experimental_caller (experimental_nextAppDirCaller ({pathExtractor : ({meta }) => (meta asMeta )?.span ?? '',}),).use (async (opts ) => {constuser = awaitcurrentUser ();returnopts .next ({ctx : {user } });});
3. 保護されたアクションプロシージャを作成
認証が必要なアクション向けの再利用可能なベースを作成するため、認可ミドルウェアを追加します:
server/trpc.tstsexport constprotectedAction =serverActionProcedure .use ((opts ) => {if (!opts .ctx .user ) {throw newTRPCError ({code : 'UNAUTHORIZED',});}returnopts .next ({ctx : {...opts .ctx ,user :opts .ctx .user , // ensures type is non-nullable},});});
server/trpc.tstsexport constprotectedAction =serverActionProcedure .use ((opts ) => {if (!opts .ctx .user ) {throw newTRPCError ({code : 'UNAUTHORIZED',});}returnopts .next ({ctx : {...opts .ctx ,user :opts .ctx .user , // ensures type is non-nullable},});});
Server Action の定義
"use server" ディレクティブを含むファイルを作成し、プロシージャビルダーを使用してアクションを定義します:
app/_actions.tsts'use server';import {z } from 'zod';import {protectedAction } from '../server/trpc';export constcreatePost =protectedAction .input (z .object ({title :z .string (),}),).mutation (async (opts ) => {// opts.ctx.user is typed as non-nullable// opts.input is typed as { title: string }// Create the post...});
app/_actions.tsts'use server';import {z } from 'zod';import {protectedAction } from '../server/trpc';export constcreatePost =protectedAction .input (z .object ({title :z .string (),}),).mutation (async (opts ) => {// opts.ctx.user is typed as non-nullable// opts.input is typed as { title: string }// Create the post...});
experimental_caller により、プロシージャは Server Action として使用できるプレーンな非同期関数になります。
クライアントコンポーネントからの呼び出し
Server Action をインポートし、クライアントコンポーネントで使用します。Server Actions はプログレッシブエンハンスメントのための action 属性と、onSubmit 経由のプログラム呼び出しの両方で動作します:
app/post-form.tsxtsx'use client';import {createPost } from '../_actions';export functionPostForm () {return (<form onSubmit ={async (e ) => {e .preventDefault ();consttitle = newFormData (e .currentTarget ).get ('title') as string;awaitcreatePost ({title });}}><input type ="text"name ="title" /><button type ="submit">Create Post</button ></form >);}
app/post-form.tsxtsx'use client';import {createPost } from '../_actions';export functionPostForm () {return (<form onSubmit ={async (e ) => {e .preventDefault ();consttitle = newFormData (e .currentTarget ).get ('title') as string;awaitcreatePost ({title });}}><input type ="text"name ="title" /><button type ="submit">Create Post</button ></form >);}
メタデータによるオブザーバビリティの追加
ロギングやトレーシングのためにアクションにタグ付けするには .meta() メソッドを使用します。メタデータの span プロパティは pathExtractor に渡されるため、オブザーバビリティツールで利用できます:
app/_actions.tsts'use server';import {z } from 'zod';import {protectedAction } from '../server/trpc';export constcreatePost =protectedAction .meta ({span : 'create-post' }).input (z .object ({title :z .string (),}),).mutation (async (opts ) => {// ...});
app/_actions.tsts'use server';import {z } from 'zod';import {protectedAction } from '../server/trpc';export constcreatePost =protectedAction .meta ({span : 'create-post' }).input (z .object ({title :z .string (),}),).mutation (async (opts ) => {// ...});
Server Actions とミューテーションの使い分け
Server Actions はすべての tRPC ミューテーションの代替ではありません。以下のトレードオフを考慮してください:
-
Server Actions を使用するケース: プログレッシブエンハンスメント(JavaScript なしで動作するフォーム)が必要な場合、またはアクションがクライアントサイドの React Query キャッシュを更新する必要がない場合。
-
useMutationを使用するケース: クライアントサイドキャッシュの更新、オプティミスティックアップデートの表示、UI での複雑なローディング/エラー状態の管理が必要な場合。
既存の tRPC API と並行して Server Actions を段階的に導入できます。API 全体を書き直す必要はありません。