Skip to content

Instantly share code, notes, and snippets.

@crazy4groovy
Last active June 12, 2023 18:45
Show Gist options
  • Save crazy4groovy/d9e3a8dc5a2d8996e66d1f7af7ac6cf8 to your computer and use it in GitHub Desktop.
Save crazy4groovy/d9e3a8dc5a2d8996e66d1f7af7ac6cf8 to your computer and use it in GitHub Desktop.
A simple hook to implement form validation (ReactJS)
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;
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