I am working with a form in react, So I created custom hook for handling form and validation, which is working fine, But I recently found some issue in that, which not good for more than one form, suppose one form is login form, and then when I login I have several other forms as well which doesn’t work in this scenario.
What I did
-
My Input field component
<form onSubmit={handleSubmit}> <input type="text" className={`${errors.fName && "input-error"}`} name="fName" id="fName" onChange={handleChange} value={values.fName || ""} />; </form>
-
I have written one useForm custom hook, to handle the changes, submit and validation as well, below is the code
import { useState, useEffect } from "react"; const useForm = (callback, validate) => { const [values, setValues] = useState({}); const [errors, setErrors] = useState({}); const [isSubmitting, setIsSubmitting] = useState(false); useEffect(() => { if (Object.keys(errors).length === 0 && isSubmitting) { callback(); } }, [errors]); const handleSubmit = (event) => { if (event) event.preventDefault(); setErrors(validate(values)); setIsSubmitting(true); }; const handleChange = (event) => { event.persist(); setValues((values) => ({ ...values, [event.target.name]: event.target.value, })); }; return { handleChange, handleSubmit, values, errors, }; }; export default useForm;
-
Now below is my validation.js file
export default function validate(values) { let errors = {}; if (!values.emailAddress) { errors.emailAddress = "Email address is required"; } if (!values.password) { errors.password = "Password is required"; } if (!values.fName) { errors.fName = "first name is required"; } if (!values.lName) { errors.lName = "last name is required"; } return errors;
}
-
Now In my main component where Input fields are declarer I am calling the useform hook and passing the click and validate function, and click function will only work after validate function. Below is how I am doing
const { values, errors, handleChange, handleSubmit } = useForm( btnClick, Validate );
Steps to recreate the issue
- In validation file I have four validate rules which are for
email address
,password
,firstname
,lastname
- Now
email address
andpassword
are in one form andfirstname
andlastname
are in other form - So when I click submit in form one it doesn’t give me the
values
because for this form two errors still exist - My thinkin is whichever form I am click submit it should validate those rules only not other form rules
What I am looking for
-
If I can do it with useRef/ref like how
https://react-hook-form.com/
is doing where there is no onchange, and if want not to give validation to any of input I will just not passref
-
I like @TusharShahi answer and will follow that, But I am looking for more options which is more of generic code
2
Answers
So this can definitely be solved using refs and modifying the validate function a bit.
While this can be done by using a single validate function, do remember it is necessary to pass to the function what field values it should be validating. Without that it would not be aware of which values to check and it would be checking for all the values.
This is how I would modify the validate function:
errMap
is just an easy config object to tell what each field value’s error would look like. The key is the name of the field and the value is the error message.Since our solution need to be extensible enough to the situation when not all fields in a single form need to be validated, the hook should also change. It needs to allow passing only the fields which need to be checked.
There are two changes:
handleSubmit
is modified to extract names that need to pass tovalidate
.Finally, passing the correct refs to the hook will complete the solution.
codesandbox link
PS:
I do not see any problem in creating two validate functions. Both can reside in the same file too. And then you can pass the correct one when invoking your hook. With the individual validate functions you need not pass the list of inputs which need to validated as your individual validate function would be catered to your form fields. I would also like to suggest that your individual validate methods should reside close to your forms. Form1 with Validate1 (in a separate file if needed).
You haven’t shown the full example, but it sounds like you’re sharing the same state between two forms.
Hooks create new state variables each time they are called. So if you want two forms with separate state, you need to call the hook twice:
Then you can give each form it’s respective properties.
Note: I don’t know what
btnClick
is, so no idea if you need two copies of that.If something doesn’t make sense, then please show the full example with both forms.