UNPKG

@shopify/react-form

Version:

Manage React forms tersely and safely-typed with no magic using React hooks

77 lines (72 loc) 2.56 kB
import { useState, useCallback } from 'react'; import { useMountedRef, useLazyRef } from '@shopify/react-hooks'; import { propagateErrors, validateAll, getValues, makeCleanFields, makeCleanDynamicLists } from '../utilities.mjs'; function useSubmit(onSubmit = noopSubmission, fieldBag, makeCleanAfterSubmit = false, dynamicListBag) { const mounted = useMountedRef(); const [submitting, setSubmitting] = useState(false); const [submitErrors, setSubmitErrors] = useState([]); const fieldBagRef = useLazyRef(() => fieldBag); fieldBagRef.current = fieldBag; const dynamicListBagRef = useLazyRef(() => dynamicListBag); const setErrors = useCallback(errors => { setSubmitErrors(errors); propagateErrors(fieldBagRef.current, errors); }, [fieldBagRef]); const submit = useCallback(async event => { const fields = fieldBagRef.current; const dynamicLists = dynamicListBagRef.current; if (event && event.preventDefault && !event.defaultPrevented) { event.preventDefault(); } const clientErrors = validateAll(fields); if (clientErrors.length > 0) { setErrors(clientErrors); return; } setSubmitting(true); const result = await onSubmit(getValues(fields)); if (mounted.current === false) { return; } setSubmitting(false); if (result.status === 'fail') { setErrors(result.errors); } else { setSubmitErrors([]); if (makeCleanAfterSubmit) { makeCleanFields(fields); makeCleanDynamicLists(dynamicLists); } } }, [fieldBagRef, dynamicListBagRef, onSubmit, mounted, setErrors, makeCleanAfterSubmit]); return { submit, submitting, errors: submitErrors, setErrors }; } /** * A convenience function for `onSubmit` callbacks returning values to `useSubmit` or `useForm`. * @return Returns a `SubmitResult` representing your successful form submission. */ function submitSuccess() { return { status: 'success' }; } /** * A convenience function for `onSubmit` callbacks returning values to `useSubmit` or `useForm` * @param errors - An array of errors with the user's input. These can either include both a `field` and a `message`, in which case they will be passed down to a matching field, or just a `message`. * @return Returns a `SubmitResult` representing your failed form submission. */ function submitFail(errors = []) { return { status: 'fail', errors }; } function noopSubmission(_) { return Promise.resolve(submitSuccess()); } export { submitFail, submitSuccess, useSubmit };