safe-action-client

安装量: 38
排名: #18555

安装

npx skills add https://github.com/next-safe-action/skills --skill safe-action-client

next-safe-action Client & Action Definition Quick Start // src/lib/safe-action.ts import { createSafeActionClient } from "next-safe-action" ; export const actionClient = createSafeActionClient ( ) ; // src/app/actions.ts "use server" ; import { z } from "zod" ; import { actionClient } from "@/lib/safe-action" ; export const greetUser = actionClient . inputSchema ( z . object ( { name : z . string ( ) . min ( 1 ) } ) ) . action ( async ( { parsedInput : { name } } ) => { return { greeting : Hello, ${ name } ! } ; } ) ; Chainable API Order createSafeActionClient(opts?) .use(middleware) // repeatable, adds middleware to chain .metadata(data) // required if defineMetadataSchema is set .inputSchema(schema, utils?) // Standard Schema or async factory function .bindArgsSchemas([...]) // schemas for .bind() arguments (order with inputSchema is flexible) .outputSchema(schema) // validates action return value .action(serverCodeFn, utils?) // creates SafeActionFn .stateAction(serverCodeFn, utils?) // creates SafeStateActionFn (for useActionState) Each method returns a new client instance — the chain is immutable. Entry Points Entry point Environment Exports next-safe-action Server createSafeActionClient , createMiddleware , returnValidationErrors , flattenValidationErrors , formatValidationErrors , DEFAULT_SERVER_ERROR_MESSAGE , error classes, all core types next-safe-action/hooks Client useAction , useOptimisticAction , hook types next-safe-action/stateful-hooks Client useStateAction (deprecated — use React's useActionState directly) Supporting Docs Client setup & configuration Input & output validation with Standard Schema Server error handling Anti-Patterns // BAD: Missing "use server" directive — action won't work import { actionClient } from "@/lib/safe-action" ; export const myAction = actionClient . action ( async ( ) => { } ) ; // GOOD: Always include "use server" in action files "use server" ; import { actionClient } from "@/lib/safe-action" ; export const myAction = actionClient . action ( async ( ) => { } ) ; // BAD: Calling .action() without .metadata() when metadataSchema is defined const client = createSafeActionClient ( { defineMetadataSchema : ( ) => z . object ( { actionName : z . string ( ) } ) , } ) ; client . action ( async ( ) => { } ) ; // TypeScript error! // GOOD: Always provide metadata before .action() when schema is defined client . metadata ( { actionName : "myAction" } ) . action ( async ( ) => { } ) ; // BAD: Returning an error instead of throwing export const myAction = actionClient . inputSchema ( z . object ( { email : z . string ( ) . email ( ) } ) ) . action ( async ( { parsedInput } ) => { const exists = await db . user . findByEmail ( parsedInput . email ) ; if ( exists ) { return { error : "Email taken" } ; // Not type-safe, not standardized } } ) ; // GOOD: Use returnValidationErrors for field-level errors import { returnValidationErrors } from "next-safe-action" ; export const myAction = actionClient . inputSchema ( z . object ( { email : z . string ( ) . email ( ) } ) ) . action ( async ( { parsedInput } ) => { const exists = await db . user . findByEmail ( parsedInput . email ) ; if ( exists ) { returnValidationErrors ( z . object ( { email : z . string ( ) . email ( ) } ) , { email : { _errors : [ "Email is already in use" ] } , } ) ; } return { success : true } ; } ) ; Server Code Function Parameters The function passed to .action() receives a single object: . action ( async ( { parsedInput , // validated input (typed from inputSchema) clientInput , // raw client input (unknown) bindArgsParsedInputs , // validated bind args tuple bindArgsClientInputs , // raw bind args ctx , // context from middleware chain metadata , // metadata set via .metadata() } ) => { // return data } ) ; For .stateAction() , a second argument is added: . stateAction ( async ( { parsedInput , ctx } , { prevResult } ) => { // prevResult is the previous SafeActionResult (structuredClone'd) return { count : ( prevResult . data ?. count ?? 0 ) + 1 } ; } ) ;

返回排行榜