Last active
June 12, 2023 18:45
-
-
Save crazy4groovy/d9e3a8dc5a2d8996e66d1f7af7ac6cf8 to your computer and use it in GitHub Desktop.
A simple hook to implement form validation (ReactJS)
This file contains 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 React from 'react'; | |
import useFormValidation from './useFormValidation'; | |
const initialValues = { | |
name: '', | |
email: '', | |
password: '', | |
}; | |
// You should put this config in a separate file! | |
const validationRules = { | |
name: [ | |
{ validator: (value) => value.trim() !== '', message: 'Name is required' }, | |
], | |
email: [ | |
{ validator: (value) => value.trim() !== '', message: 'Email is required' }, | |
{ validator: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value), message: 'Invalid email format' }, | |
], | |
password: [ | |
{ validator: (value) => value.trim() !== '', message: 'Password is required' }, | |
{ validator: (value) => value.length >= 6, message: 'Password must be at least 6 characters' }, | |
], | |
}; | |
const App = () => { | |
const { | |
values, | |
errors, | |
touchedFields, | |
handleChange, | |
handleBlur, | |
validateForm, | |
resetForm, | |
} = useFormValidation(initialValues, validationRules); | |
const handleSubmit = (evt) => { | |
evt.preventDefault(); | |
// Validate the form before submitting | |
const errors = validateForm(); | |
if (Object.values(errors).length > 0) { | |
// Form is invalid, display validation errors | |
console.log('Form validation errors:', errors); | |
return; | |
} | |
// Form is valid, perform form submission logic | |
console.log('Form submitted:', values); | |
// ... | |
resetForm(); | |
}; | |
return ( | |
<div> | |
<h1>Example Form</h1> | |
<form onSubmit={handleSubmit}> | |
<div> | |
<label>Name:</label> | |
<input | |
type="text" | |
name="name" | |
value={values.name} | |
onChange={handleChange} | |
onBlur={handleBlur} | |
/> | |
{touchedFields.name && errors.name && <p>{errors.name}</p>} | |
</div> | |
<div> | |
<label>Email:</label> | |
<input | |
type="email" | |
name="email" | |
value={values.email} | |
onChange={handleChange} | |
onBlur={handleBlur} | |
/> | |
{touchedFields.email && errors.email && <p>{errors.email}</p>} | |
</div> | |
<div> | |
<label>Password:</label> | |
<input | |
type="password" | |
name="password" | |
value={values.password} | |
onChange={handleChange} | |
onBlur={handleBlur} | |
/> | |
{touchedFields.password && errors.password && <p>{errors.password}</p>} | |
</div> | |
<button type="submit">Submit</button> | |
</form> | |
</div> | |
); | |
}; | |
export default App; |
This file contains 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 { useState } from 'react'; | |
const clone = obj => JSON.parse(JSON.stringify(obj)) | |
const useFormValidation = (initialValues, validationRules) => { | |
const [resetValues, setResetValues] = useState(initialValues); | |
const [values, setValues] = useState(initialValues); | |
const [errors, setErrors] = useState({}); | |
const [touchedFields, setTouchedFields] = useState({}); | |
const handleChange = (evt) => { | |
const { name, value } = evt.target; | |
setValues((prevValues) => ({ ...prevValues, [name]: value })); | |
_validateField(name); | |
}; | |
const handleBlur = (evt) => { | |
const { name } = evt.target; | |
setTouchedFields((prevTouchedFields) => ({ ...prevTouchedFields, [name]: true })); | |
_validateField(name); | |
}; | |
const _validateField = (field) => { | |
if (validationRules[field] === undefined) { | |
return; | |
} | |
const fieldValue = values[field]; | |
const fieldError = validationRules[field] | |
.find(({ validator, message }) => validator(fieldValue) ? undefined : message) | |
if (errors[field] === fieldError) return; | |
setErrors((prevErrors) => clone({ ...prevErrors, [field]: fieldError })); // note: clone used to remove undefined values | |
}; | |
const validateForm = () => { | |
const newErrors = {}; | |
for (const field in validationRules) { | |
const fieldValue = values[field]; | |
const fieldError = validationRules[field] | |
.find(({ validator, message }) => validator(fieldValue) ? undefined : message) | |
if (fieldError !== undefined) { | |
newErrors[field] = fieldError; | |
} | |
} | |
if (JSON.stringify(newErrors) !== JSON.stringify(errors)) { | |
setErrors(newErrors); | |
} | |
return newErrors; | |
}; | |
const resetForm = (resetValuesNew) => { | |
setResetValues(resetValuesNew ?? resetValues) | |
setValues(resetValuesNew ?? resetValues); | |
setErrors({}); | |
setTouchedFields({}); | |
}; | |
return { | |
values, | |
errors, | |
touchedFields, | |
handleChange, | |
handleBlur, | |
validateForm, | |
resetForm, | |
}; | |
}; | |
export default useFormValidation; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment