Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Seamlessly integrate next-safe-action with react-hook-form.

License

NotificationsYou must be signed in to change notification settings

next-safe-action/adapter-react-hook-form

Repository files navigation

This adapter offers a way to seamlessly integratenext-safe-action withreact-hook-form.

Requirements

  • React >=18.2.0
  • Next.js >=14.0.0
  • next-safe-action >=7.6.0
  • react-hook-form >=7.0.0
  • @hookform/resolvers >=3.0.0

Installation

npm i next-safe-action react-hook-form @hookform/resolvers @next-safe-action/adapter-react-hook-form

Example

The best way to learn how to use this adapter is to take a look at the examples. Theapp in this repository shows you how to use theuseHookFormAction anduseHookFormOptimisticAction hooks:

Hooks

useHookFormAction

This hook is a wrapper arounduseAction from next-safe-action anduseForm from react-hook-form that makes it much easier to use safe actions with react-hook-form. It also maps validation errors toFieldErrors compatible with react-hook-form.

Example (login)

  1. First of all, we need a shared file to store our validation schema(s). In this case, theloginSchema Zod validator is exported fromvalidation.ts:
import{z}from"zod";exportconstloginSchema=z.object({username:z.string().min(3).max(30),password:z.string().min(8).max(100),});
  1. Then, we can create our login action usingloginSchema:
"use server";import{returnValidationErrors}from"next-safe-action";import{actionClient}from"@/lib/safe-action";import{loginSchema}from"./validation";import{checkCredentials}from"@/services/auth";exportconstloginAction=actionClient.schema(loginSchema).action(async({ parsedInput})=>{constvalid=awaitcheckCredentials(parsedInput.username,parsedInput.password);// If the credentials are invalid, return root validation error.if(!valid){returnValidationErrors(loginSchema,{_errors:["Invalid username or password"],});}return{successful:true,};});
  1. Finally, we can useuseHookFormAction in our Client Component, by passing to it theloginSchema andloginAction declared above:
"use client";import{useHookFormAction}from"@next-safe-action/adapter-react-hook-form/hooks";import{zodResolver}from"@hookform/resolvers/zod";import{loginSchema}from"./validation";import{loginAction}from"./login-action";exportfunctionLoginForm(){const{ form, action, handleSubmitWithAction, resetFormAndAction}=useHookFormAction(loginAction,zodResolver(loginSchema),{actionProps:{},formProps:{},errorMapProps:{},});return<formonSubmit={handleSubmitWithAction}>...</form>;}

Parameters

  • safeAction: the safe action (required)
  • hookFormResolver: a react-hook-form validation resolver (required)
  • props: props foruseAction,useForm and error mapper (optional)

Return values (object)

  • form: the react-hook-form form
  • action: the next-safe-action action
  • handleSubmitWithAction: a function that handles form submission by automatically executing the action
  • resetFormAndAction: a function that resets the form and the action state

useHookFormOptimisticAction

This hook is a wrapper arounduseOptimisticAction from next-safe-action anduseForm from react-hook-form that makes it much easier to use safe actions with react-hook-form. It also maps validation errors toFieldErrors compatible with react-hook-form.

Example (add todo)

  1. First of all, we need a shared file to store our validation schema(s). In this case, theaddTodoSchema Zod validator is exported fromvalidation.ts:
import{z}from"zod";exportconstaddTodoSchema=z.object({newTodo:z.string().min(1).max(200),});
  1. Then, we can create our add todo action usingaddTodoSchema:
"use server";import{returnValidationErrors}from"next-safe-action";import{revalidatePath}from"next/cache";import{actionClient}from"@/lib/safe-action";import{addTodoSchema}from"./validation";import{badWordsCheck}from"@/utils";import{saveTodoInDb}from"@/services/db";exportconstaddTodoAction=actionClient.schema(addTodoSchema).action(async({ parsedInput})=>{constcontainsBadWords=badWordsCheck(parsedInput.newTodo);// If the todo conif(containsBadWords){returnValidationErrors(addTodoSchema,{newTodo:{_errors:["The todo contains bad words!"],},});}awaitsaveTodoInDb(parsedInput.newTodo);revalidatePath("/");return{newTodo:parsedInput.newTodo,};});
  1. Finally, we can useuseHookFormOptimisticAction in our Client Component, by passing to it theaddTodoSchema andaddTodoAction declared above:
"use client";import{useHookFormOptimisticAction}from"@next-safe-action/adapter-react-hook-form/hooks";import{zodResolver}from"@hookform/resolvers/zod";import{addTodoSchema}from"./validation";import{addTodoAction}from"./addtodo-action";typeProps={todos:string[];};// Todos are passed from the parent Server Component and updated each time a new todo is added// thanks to the `revalidatePath` function called inside the action.exportfunctionAddTodoForm({ todos}:Props){const{ form, action, handleActionSubmit, resetFormAndAction}=useHookFormOptimisticAction(addTodoAction,zodResolver(addTodoSchema),{actionProps:{currentState:{todos,},updateFn:(state,input)=>{return{todos:[...state.todos,input.newTodo],};},},formProps:{},errorMapProps:{},});return<formonSubmit={handleActionSubmit}></form>;}

Parameters

  • safeAction: the safe action (required)
  • hookFormResolver: a react-hook-form validation resolver (required)
  • props: props foruseOptimisticAction,useForm and error mapper.actionProps.currentState andactionProps.updateFn are required by theuseOptimisticAction hook used under the hood, the rest are optional. (required/optional)

Return values (object)

  • form: the react-hook-form form
  • action: the next-safe-action action
  • handleSubmitWithAction: a function that handles form submission by automatically executing the action
  • resetFormAndAction: a function that resets the form and the action state

useHookFormActionErrorMapper

For more control over the execution flow, you can use this hook to get back the memoized mapped validation errors of the action. It can be useful for cases when you need to use bothuseAction anduseForm in your Client Component, for a particular task, or when you want to create custom hooks.

Example (Client Component)

  1. We'll reuse theloginSchema andloginAction from theuseHookFormAction example here.

  2. Here's how you would useuseHookFormActionErrorMapper in your Client Component:

"use client";import{useHookFormActionErrorMapper}from"@next-safe-action/adapter-react-hook-form/hooks";import{zodResolver}from"@hookform/resolvers/zod";import{loginSchema}from"./validation";import{loginAction}from"./login-action";import{useAction}from"next-safe-action/hooks";import{useForm}from"react-hook-form";import{Infer}from"next-safe-action/adapters/types";exportfunctionCustomForm(){constaction=useAction(loginAction);const{ hookFormValidationErrors}=useHookFormActionErrorMapper<typeofloginSchema>(action.result.validationErrors,{joinBy:"\n"});constform=useForm<Infer<typeofloginSchema>>({resolver:zodResolver(loginSchema),errors:hookFormValidationErrors,});return<formonSubmit={form.handleSubmit(action.executeAsync)}>...</form>;}

Parameters

  • validationErrors: next-safe-action object ofValidationErrors, orundefined (required)
  • props:joinBy fromErrorMapperProps type. It's used to determine how to join the error messages, if more than one is present in the errors array. It defaults to" " (optional)

Return values (object)

  • hookFormValidationErrors: object of mapped errors withFieldErrors type, compatible with react-hook-form

Utilities

mapToHookFormErrors

For more advanced stuff, you can directly use themapToHookFormErrors function that is utilized under the hood to map next-safe-actionValidationErrors to react-hook-form compatibleFieldErrors.

Example

import{mapToHookFormErrors}from"@next-safe-action/adapter-react-hook-form";import{loginAction}from"./login-action";importtype{loginSchema}from"./validation";asyncfunctionadvancedStuff(){constresult=awaitloginAction({username:"foo",password:"bar"});consthookFormValidationErrors=mapToHookFormErrors<typeofloginSchema>(result?.validationErrors,{joinBy:"\n"});// Do something with `hookFormValidationErrors`...}

Parameters

  • validationErrors: next-safe-action object ofValidationErrors, orundefined (required)
  • props:joinBy fromErrorMapperProps type. It's used to determine how to join the error messages, if more than one is present in the errors array. It defaults to" " (optional)

Return value

  • mapped errors: object of mapped errors withFieldErrors type, compatible with react-hook-form

Types

/

ErrorMapperProps

Props formapToHookFormErrors. Also used by the hooks.

exporttypeErrorMapperProps={joinBy?:string;};

/hooks

HookProps

Optional props foruseHookFormAction anduseHookFormOptimisticAction.

exporttypeHookProps<ServerError,SextendsStandardSchemaV1|undefined,CVE,Data,FormContext=any>={errorMapProps?:ErrorMapperProps;actionProps?:HookCallbacks<ServerError,S,CVE,Data>;formProps?:Omit<UseFormProps<InferInputOrDefault<S,any>,FormContext,InferOutputOrDefault<S,any>>,"resolver">;};

UseHookFormActionHookReturn

Type of the return object of theuseHookFormAction hook.

exporttypeUseHookFormActionHookReturn<ServerError,SextendsStandardSchemaV1|undefined,CVE,Data,FormContext=any,>={action:UseActionHookReturn<ServerError,S,CVE,Data>;form:UseFormReturn<InferInputOrDefault<S,any>,FormContext,InferOutputOrDefault<S,any>>;handleSubmitWithAction:(e?:React.BaseSyntheticEvent)=>Promise<void>;resetFormAndAction:()=>void;};

UseHookFormOptimisticActionHookReturn

Type of the return object of theuseHookFormOptimisticAction hook.

exporttypeUseHookFormOptimisticActionHookReturn<ServerError,SextendsStandardSchemaV1|undefined,CVE,Data,State,FormContext=any,>=Omit<UseHookFormActionHookReturn<ServerError,S,CVE,Data,FormContext>,"action">&{action:UseOptimisticActionHookReturn<ServerError,S,CVE,Data,State>;};

Infer types

You can use these utility types exported from the/hooks path to infer the return types of the hooks.

InferUseHookFormActionHookReturn

Infer the type of the return object of theuseHookFormAction hook.

exporttypeInferUseHookFormActionHookReturn<TextendsFunction,FormContext=any>=TextendsSafeActionFn<inferServerError,inferSextendsSchema|undefined,inferBASextendsreadonlySchema[],inferCVE,inferCBAVE,inferData>?UseHookFormActionHookReturn<ServerError,S,BAS,CVE,CBAVE,Data,FormContext>:never;

InferUseHookFormOptimisticActionHookReturn

Infer the type of the return object of theuseHookFormOptimisticAction hook.

exporttypeInferUseHookFormOptimisticActionHookReturn<TextendsFunction,State,FormContext=any>=TextendsSafeActionFn<inferServerError,inferSextendsSchema|undefined,inferBASextendsreadonlySchema[],inferCVE,inferCBAVE,inferData>?UseHookFormOptimisticActionHookReturn<ServerError,S,BAS,CVE,CBAVE,Data,State,FormContext>:never;

License

This project is released under theMIT License.


[8]ページ先頭

©2009-2025 Movatter.jp