Server Actions
Denna sida har översatts av PageTurner AI (beta). Inte officiellt godkänd av projektet. Hittade du ett fel? Rapportera problem →
Server Actions låter dig definiera funktioner på servern och anropa dem direkt från klientkomponenter, med nätverkslagret abstraherat bort av ramverket.
Genom att definiera dina server actions med tRPC-procedurer får du alla tRPC:s inbyggda funktioner: validering av indata, autentisering och auktorisering via middleware, validering av utdata, datatransformeringar med mera.
Server Actions-integrationen använder prefixet experimental_ och är fortfarande under aktiv utveckling. API:t kan komma att ändras i framtida versioner.
Konfigurera Server Action-procedurer
1. Definiera en basprocedur med experimental_caller
Använd experimental_caller på en procedurbuilder tillsammans med experimental_nextAppDirCaller för att skapa procedurer som kan anropas som vanliga funktioner (server actions). Alternativet pathExtractor låter dig identifiera procedurer via metadata, vilket är användbart för loggning och observability eftersom server actions saknar router-sökvägar som 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. Lägg till kontext via middleware
Eftersom server actions inte passerar genom en HTTP-adapter finns det ingen createContext för att injicera kontext. Använd istället en middleware för att tillhandahålla kontext som sessionsdata:
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. Skapa en skyddad action-procedur
Lägg till en auktoriseringsmiddleware för att skapa en återanvändbar bas för actions som kräver autentisering:
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},});});
Definiera en server action
Skapa en fil med direktivet "use server" och definiera din action med procedurbuildern:
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...});
På grund av experimental_caller är proceduren nu en vanlig asynkron funktion som kan användas som server action.
Anropa från klientkomponenter
Importera server action:en och använd den i en klientkomponent. Server actions fungerar både med action-attributet för progressiv förbättring och programmatiska anrop via 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 >);}
Lägg till observability med metadata
Använd metoden .meta() för att tagga actions för loggning eller spårning. span-egenskapen från metadatan skickas till pathExtractor, så den kan användas av observability-verktyg:
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 ) => {// ...});
När Server Actions är att föredra framför mutations
Server Actions är inte en ersättning för alla tRPC-mutations. Tänk på avvägningarna:
-
Använd Server Actions när du vill ha progressiv förbättring (formulär som fungerar utan JavaScript), eller när action:en inte behöver uppdatera React Query-cachen på klientsidan.
-
Använd
useMutationnär du behöver uppdatera klient-sidans cache, visa optimistiska uppdateringar eller hantera komplexa laddnings-/felstatusar i användargränssnittet.
Du kan adoptera server actions stegvis bredvid ditt befintliga tRPC-API - det finns inget behov av att skriva om hela ditt API.