Created
December 1, 2022 22:23
-
-
Save zourdyzou/cdb53aee53d006afdaa92af4c14b9c14 to your computer and use it in GitHub Desktop.
Form Validation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { ChangeEvent, FormEvent, useState } from 'react'; | |
| interface Validation { | |
| required?: { | |
| value: boolean; | |
| message: string; | |
| }; | |
| pattern?: { | |
| value: string; | |
| message: string; | |
| }; | |
| custom?: { | |
| isValid: (value: string) => boolean; | |
| message: string; | |
| }; | |
| } | |
| type ErrorRecord<T> = Partial<Record<keyof T, string>>; | |
| type Validations<T extends {}> = Partial<Record<keyof T, Validation>>; | |
| export const useForm = <T extends Record<keyof T, any> = {}>(options?: { | |
| validations?: Validations<T>; | |
| initialValues?: Partial<T>; | |
| onSubmit?: () => void; | |
| }) => { | |
| const [data, setData] = useState<T>((options?.initialValues || {}) as T); | |
| const [errors, setErrors] = useState<ErrorRecord<T>>({}); | |
| // Needs to extend unknown so we can add a generic to an arrow function | |
| const handleChange = <S extends unknown>( | |
| key: keyof T, | |
| sanitizeFn?: (value: string) => S | |
| ) => (e: ChangeEvent<HTMLInputElement & HTMLSelectElement>) => { | |
| const value = sanitizeFn ? sanitizeFn(e.target.value) : e.target.value; | |
| setData({ | |
| ...data, | |
| [key]: value, | |
| }); | |
| }; | |
| const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { | |
| e.preventDefault(); | |
| const validations = options?.validations; | |
| if (validations) { | |
| let valid = true; | |
| const newErrors: ErrorRecord<T> = {}; | |
| for (const key in validations) { | |
| const value = data[key]; | |
| const validation = validations[key]; | |
| if (validation?.required?.value && !value) { | |
| valid = false; | |
| newErrors[key] = validation?.required?.message; | |
| } | |
| const pattern = validation?.pattern; | |
| if (pattern?.value && !RegExp(pattern.value).test(value)) { | |
| valid = false; | |
| newErrors[key] = pattern.message; | |
| } | |
| const custom = validation?.custom; | |
| if (custom?.isValid && !custom.isValid(value)) { | |
| valid = false; | |
| newErrors[key] = custom.message; | |
| } | |
| } | |
| if (!valid) { | |
| setErrors(newErrors); | |
| return; | |
| } | |
| } | |
| setErrors({}); | |
| if (options?.onSubmit) { | |
| options.onSubmit(); | |
| } | |
| }; | |
| return { | |
| data, | |
| handleChange, | |
| handleSubmit, | |
| errors, | |
| }; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment