Custom Hook for Form Handling

JavaScript Intermediate 👁️ 2,416 views By system Added Just now

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.