JAVASCRIPT

Build Dynamic Forms with Input Management and Validation using useForm

A custom React hook for handling multiple form input states and their validation, simplifying form management in complex applications.

import { useState, useCallback } from 'react';

function useForm(initialValues, validate) {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});
  const [isSubmitting, setIsSubmitting] = useState(false);

  const handleChange = useCallback((event) => {
    event.persist();
    setValues((prevValues) => ({
      ...prevValues,
      [event.target.name]: event.target.value,
    }));
    // Clear error for the changed field
    if (errors[event.target.name]) {
      setErrors((prevErrors) => ({
        ...prevErrors,
        [event.target.name]: undefined,
      }));
    }
  }, [errors]); // Dependency on errors to clear them when field changes

  const handleSubmit = useCallback(async (callback) => {
    setIsSubmitting(true);
    const newErrors = validate ? validate(values) : {};
    setErrors(newErrors);

    if (Object.keys(newErrors).length === 0) {
      await callback(values);
    }
    setIsSubmitting(false);
  }, [values, validate]);

  const resetForm = useCallback(() => {
    setValues(initialValues);
    setErrors({});
    setIsSubmitting(false);
  }, [initialValues]);

  return {
    values,
    errors,
    isSubmitting,
    handleChange,
    handleSubmit,
    resetForm,
    setValues, // Allow external modification if needed
    setErrors, // Allow external modification if needed
  };
}

export default useForm;

// Example Usage:
// import React from 'react';
// import useForm from './useForm';
//
// const validateLoginForm = (values) => {
//   const errors = {};
//   if (!values.email) {
//     errors.email = 'Email is required';
//   } else if (!/\S+@\S+\.\S+/.test(values.email)) {
//     errors.email = 'Email address is invalid';
//   }
//   if (!values.password) {
//     errors.password = 'Password is required';
//   } else if (values.password.length < 6) {
//     errors.password = 'Password needs to be 6 characters or more';
//   }
//   return errors;
// };
//
// function LoginForm() {
//   const {
//     values,
//     errors,
//     handleChange,
//     handleSubmit,
//     isSubmitting,
//     resetForm
//   } = useForm(
//     { email: '', password: '' },
//     validateLoginForm
//   );
//
//   const onSubmit = async (formValues) => {
//     console.log('Submitting:', formValues);
//     // Simulate API call
//     await new Promise(resolve => setTimeout(resolve, 1000));
//     alert('Login successful!');
//     resetForm();
//   };
//
//   return (
//     <form onSubmit={(e) => { e.preventDefault(); handleSubmit(onSubmit); }}>
//       <div>
//         <label>Email:</label>
//         <input
//           type="email"
//           name="email"
//           value={values.email}
//           onChange={handleChange}
//         />
//         {errors.email && <p style={{ color: 'red' }}>{errors.email}</p>}
//       </div>
//       <div>
//         <label>Password:</label>
//         <input
//           type="password"
//           name="password"
//           value={values.password}
//           onChange={handleChange}
//         />
//         {errors.password && <p style={{ color: 'red' }}>{errors.password}</p>}
//       </div>
//       <button type="submit" disabled={isSubmitting}>
//         {isSubmitting ? 'Submitting...' : 'Login'}
//       </button>
//       <button type="button" onClick={resetForm}>Reset</button>
//     </form>
//   );
// }
// export default LoginForm;
How it works: The `useForm` hook provides a robust solution for managing form state, validation, and submission logic. It initializes form values and errors, offers a `handleChange` function for input updates, and a `handleSubmit` function that runs a provided validation callback before executing the submission logic. `useCallback` is used to memoize functions, preventing unnecessary re-renders, while `useState` manages the form data, validation errors, and submission status.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs