skip to Main Content

**i have been stuck with this issue where i am getting this error i have made this custom hooks for validation which i wanted to use in registration form..
**

import { useState } from 'react'

function useValidate(formData) {

    const [isValid,setIsValid] = useState(true);

    console.log(formData)

    if(formData.fName === ''){
        setIsValid(false);
        console.log('fname')
    }
    else if(formData.lName === ''){
        setIsValid(false);
        console.log('lname')
    }
        return isValid


}

export default useValidate

This is my registartion form where i am calling this custom hook named useValidate but it throwing error

i have passed formData as parameter to the useValidate hook and using that i am validate my form

import React, { useState } from 'react'
import useValidate from '../hooks/useValidate'

function Form() {
    const [formData, setFormData] = useState({
        fName:'',
        lName:'',
    })

    const isValid = useValidate(formData)

    const handleChange = (e) =>{
        setFormData({...formData,id:new Date().getMilliseconds().toString(),[e.target.name]:e.target.value})
        console.log(formData)
    }

    const handleSubmit = (e) =>{
        e.preventDefault();
        if(isValid){
            alert('success')
        }
        else{
            alert('fill the blank input')
        }
    }

 
    return (
        <div className='container col-5 my-5'>
            <h1>Registration</h1>
            <div className="mb-3">
                <label htmlFor="fName" className="form-label">First Name</label>
                <input type="text" className="form-control" id="fName" name='fName'  value={formData.fName} onChange={handleChange}/>
            </div>
            <div className="mb-3">
                <label htmlFor="lName" className="form-label">Last Name</label>
                <input type="text" className="form-control" id="lName" name='lName' value={formData.lName} onChange={handleChange} />
            </div>

            <div className="mb-3">
                <button className='btn btn-success' type='submit' onClick={handleSubmit}>Register</button>
            </div>
        </div>

    )
}

export default Form```

3

Answers


  1. import { useState } from 'react'
    
    function useValidate(formData) {
        const isValid = useMemo(() => {
           return formData.fName && formData.lName;
        }, [formData]);
    
        return isValid
    }
    
    export default useValidate
    
    Login or Signup to reply.
  2. Too many re-renders

    This is actually the hint to what is happening here. Because you called your state setter immediately inside the useValidate function, React triggers a re render causing infinite re-renders.

    console.log(formData)
    
    // this code triggers our re-render
    if (formData.fName === '') {
        setIsValid(false);
        console.log('fname') 
    } else if (formData.lName === '') {
        setIsValid(false);
        console.log('lname')
    }
    return isValid
    

    To solve this problem, what I did was to wrap our logic in a useEffect hook and added formData as a dependency. What your custom hook would look like will be something like this:

    function useValidate(formData) {
        const [isValid, setIsValid] = useState(true);
    
        console.log(formData);
    
        useEffect(() => {
            if (formData.fName === '') {
                setIsValid(false);
                console.log('fname');
            } else if (formData.lName === '') {
                setIsValid(false);
                console.log('lname');
            }
        }, [formData])
    
        return isValid;
    }
    

    This would make your hook only check once and everytime formData changes, do take note that when putting an object as a dependency in the useEffect hook, React only re-renders if the object reference is different.

    Login or Signup to reply.
  3. First you tried it nicely. In your Validate Hook there are multiple problems:

    1. Always return in {} so you can return multiple states and functions.
    2. If else condition of formData should be in a separate function that should be called in handleSubmit function.
    3. Its better to use arrow function (not necessary) for component.

    Here is the code that works perfect.

    USEVALIDATE

    import { useState } from 'react';
    
    const useValidate=()=>{
      const [validationResults, setValidationResults] = useState({ fName: true, lName: true });
    
      const validateForm = (formData) => {
        const results = {
          fName: formData.fName !== '',
          lName: formData.lName !== '',
        };
        setValidationResults(results);
        return results;
      };
    
      return {
        validateForm,
        validationResults,
      };
    }
    
    export default useValidate;
    

    FORM.js

    import React, { useState } from 'react';
    import useValidate from '../hooks/useValidate';
    
    function Form() {
      const [formData, setFormData] = useState({
        fName: '',
        lName: '',
      });
    
      const { validateForm, validationResults } = useValidate();
    
      const handleChange = (e) => {
        setFormData({ ...formData, [e.target.name]: e.target.value });
      };
    
      const handleSubmit = (e) => {
        e.preventDefault();
        const results = validateForm(formData);
        if (results.fName && results.lName) {
          alert('success');
        } else {
          alert('fill the blank input');
        }
      };
    
      return (
        // ... your JSX code ...
      );
    }
    
    export default Form;
    

    Happy coding.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search