Custom Hook for Form Handling
Reusable form state management with validation
0
JavaScript Code
import { useState, useCallback, useMemo } from "react";
function useForm(initialValues = {}, validationRules = {}, onSubmit) {
const [values, setValues] = useState(initialValues);
const [errors, setErrors] = useState({});
const [touched, setTouched] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const validateField = useCallback((name, value) => {
const rules = validationRules[name];
if (!rules) return "";
for (const rule of rules) {
if (rule.required && !value) return rule.message;
if (rule.minLength && value.length < rule.minLength) return rule.message;
if (rule.pattern && !rule.pattern.test(value)) return rule.message;
}
return "";
}, [validationRules]);
const handleChange = useCallback((e) => {
const { name, value, type, checked } = e.target;
const fieldValue = type === "checkbox" ? checked : value;
setValues(prev => ({ ...prev, [name]: fieldValue }));
if (touched[name]) {
const error = validateField(name, fieldValue);
setErrors(prev => ({ ...prev, [name]: error }));
}
}, [touched, validateField]);
const handleBlur = useCallback((e) => {
const { name } = e.target;
setTouched(prev => ({ ...prev, [name]: true }));
const error = validateField(name, values[name]);
setErrors(prev => ({ ...prev, [name]: error }));
}, [values, validateField]);
const handleSubmit = useCallback(async (e) => {
e?.preventDefault();
// Validate all fields
const newErrors = {};
Object.keys(validationRules).forEach(fieldName => {
const error = validateField(fieldName, values[fieldName]);
if (error) newErrors[fieldName] = error;
});
setErrors(newErrors);
if (Object.keys(newErrors).length === 0) {
setIsSubmitting(true);
try {
await onSubmit?.(values);
} finally {
setIsSubmitting(false);
}
}
}, [values, validateField, onSubmit]);
const isValid = useMemo(() => {
return Object.values(errors).every(error => !error);
}, [errors]);
return {
values,
errors,
touched,
isSubmitting,
isValid,
handleChange,
handleBlur,
handleSubmit,
setFieldValue: (name, value) => setValues(prev => ({ ...prev, [name]: value }))
};
}
export default useForm;
Explanation
This custom React hook provides complete form state management with validation, similar to Formik or React Hook Form. It handles change events, blur events, validation, submission, and error states. The hook returns everything needed for controlled components.