/
githubmirror
/
react-hook-form
Обзор
Документация
Войти
/
githubmirror
/
react-hook-form
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/form.tsx
167 строк
4 KB
Bill
🐲 feat: enhance <Form /> submit (#13605)
25 июл 2026, 04:18
Не верифицирован
25 июл 2026, 04:18
86c529a
Код
Авторство
О чём код?
import React from 'react'; import { jsonToFormData } from './utils/formData'; import isFunction from './utils/isFunction'; import isString from './utils/isString'; import { safeJSONStringify } from './utils/json'; import noop from './utils/noop'; import type { FieldValues, FormProps } from './types'; import { useFormContext } from './useFormContext'; const POST_REQUEST = 'post'; function defaultValidateStatus(status: number) { return status >= 200 && status < 300; } /** * Form component to manage submission. * * @param props - to setup submission detail. {@link FormProps} * * @returns form component or headless render prop. * * @example * ```tsx * function App() { * const { control, formState: { errors } } = useForm(); * * return ( * <Form action="/api" control={control}> * <input {...register("name")} /> * <p>{errors?.root?.server && 'Server error'}</p> * <button>Submit</button> * </Form> * ); * } * ``` */ function Form< TFieldValues extends FieldValues, TTransformedValues = TFieldValues, >(props: FormProps<TFieldValues, TTransformedValues>): React.ReactNode { const methods = useFormContext<TFieldValues, any, TTransformedValues>(); const [mounted, setMounted] = React.useState(false); const { control = methods.control, onSubmit = noop, children, action, method = POST_REQUEST, headers, encType, onError = noop, render, onSuccess = noop, validateStatus = defaultValidateStatus, ...rest } = props; const handleSubmit = React.useMemo(() => { return control.handleSubmit(async (data, event) => { const formData = jsonToFormData(data); const formDataJson = safeJSONStringify(data); if (onSubmit) { await onSubmit({ data, event, method, formData, formDataJson, }); } if (isString(action)) { try { const shouldStringifySubmissionData = (headers && headers['Content-Type'] && headers['Content-Type'].includes('json')) || (encType && encType.includes('json')); const response = await fetch(action, { method, headers: { ...headers, ...(encType && encType !== 'multipart/form-data' && { 'Content-Type': encType, }), }, body: shouldStringifySubmissionData ? formDataJson : formData, }); if (response && !validateStatus(response.status)) { onError({ response }); return { type: String(response.status) }; } else { onSuccess({ response }); } } catch (error: unknown) { onError({ error }); return { type: '' }; } } if (isFunction(action)) { try { await action(formData); } catch (error: unknown) { onError({ error }); return { type: '' }; } } // Return nothing when successful. return; }); }, [ control, onSubmit, method, action, headers, encType, validateStatus, onError, onSuccess, ]); const submit = React.useCallback( async (event?: React.BaseSyntheticEvent) => { const err = await handleSubmit(event); if (err && control) { control._subjects.state.next({ isSubmitSuccessful: false }); control.setError('root.server', err); } }, [handleSubmit, control], ); React.useEffect(() => { setMounted(true); }, []); if (render) { return render({ submit }); } // React forbids passing `method`/`encType` alongside a function `action` // (a Server-Action-style submission) -- it manages those itself and warns // if they're present, so they're only rendered for string/URL actions. return ( <form noValidate={mounted} action={action} {...(!isFunction(action) && { method, encType })} onSubmit={submit} {...rest} > {children} </form> ); } export { Form };