0

**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
    Your `useValidate` hook calls `setIsValid` every time it runs, and `setIsValid` (a state update) triggers a re-render, which causes `useValidate` to run again, resulting in an infinite loop. – ray Jul 26 '23 at 05:28

3 Answers3

0
import { useMemo } from 'react'

function useValidate(formData) {
    const isValid = useMemo(() => {
       return formData.fName && formData.lName;
    }, [formData]);

    return isValid
}

export default useValidate
Zack
  • 275
  • 5
  • 2
    Although this code might answer the question, I recommend that you also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. – Mark Rotteveel Aug 11 '23 at 10:58
0

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.

kenny019
  • 138
  • 7
0

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.

  • its worked,but what if we have multiple inputs like email and password and wanted to use regex and also want to show errors? can we have some easy and efficient way to do this?? too make it less coded and more dynamic – parth shinde Jul 27 '23 at 11:42
  • I feel like this answer does not really answer the question of why OP is getting too many re-renders. @parthshinde for your question about multiple inputs and making the hook more dynamic, you can always pass in the ref of the input/field and the validation logic as an argument. – kenny019 Jul 28 '23 at 01:59