diff --git a/examples/react/next-server-actions/src/app/client-component.tsx b/examples/react/next-server-actions/src/app/client-component.tsx index b7e62909c..d7fc43675 100644 --- a/examples/react/next-server-actions/src/app/client-component.tsx +++ b/examples/react/next-server-actions/src/app/client-component.tsx @@ -2,7 +2,7 @@ import { useActionState } from 'react' import { mergeForm, useForm, useTransform } from '@tanstack/react-form' -import { initialFormState } from '@tanstack/react-form/nextjs' +import { initialFormState, useActionSubmit } from '@tanstack/react-form/nextjs' import { useStore } from '@tanstack/react-store' import someAction from './action' import { formOpts } from './shared-code' @@ -18,10 +18,11 @@ export const ClientComp = () => { ), }) + const onActionSubmit = useActionSubmit(form) const formErrors = useStore(form.store, (formState) => formState.errors) return ( -
form.handleSubmit()}> + {formErrors.map((error) => (

{error}

))} diff --git a/packages/react-form/src/nextjs/index.ts b/packages/react-form/src/nextjs/index.ts index c839700b1..a8d06d89a 100644 --- a/packages/react-form/src/nextjs/index.ts +++ b/packages/react-form/src/nextjs/index.ts @@ -3,3 +3,4 @@ export * from '@tanstack/form-core' export * from './createServerValidate' export * from './error' export * from './types' +export * from './useActionSubmit' diff --git a/packages/react-form/src/nextjs/useActionSubmit.ts b/packages/react-form/src/nextjs/useActionSubmit.ts new file mode 100644 index 000000000..02c877220 --- /dev/null +++ b/packages/react-form/src/nextjs/useActionSubmit.ts @@ -0,0 +1,33 @@ +import { useCallback, useRef } from 'react' +import type { FormEventHandler } from 'react' +import type { FormApi } from '@tanstack/form-core' + +export const useActionSubmit = ( + form: FormApi, +) => { + const isActionSubmittedRef = useRef(false) + + const onActionSubmit = useCallback( + (submitMeta?: TSubmitMeta): FormEventHandler => { + return async (event) => { + if (isActionSubmittedRef.current) { + isActionSubmittedRef.current = false + return + } + + event.preventDefault() + + await new Promise((resolve) => setTimeout(resolve)) + await (submitMeta ? form.handleSubmit(submitMeta) : form.handleSubmit()) + + if (form.state.isValid) { + isActionSubmittedRef.current = true + ;(event.target as HTMLFormElement).requestSubmit() + } + } + }, + [form], + ) + + return onActionSubmit +}