React: enable signup button after filling out a form in React - reactjs

I wanna activate the button after I check all the inputs from the user by the function ValidateForm(). If all of fields are correct due to validateForm(), then I can see the green button activate. The problem: how can I check ALL of the fields after finishing filling out, and not only when I fill out the first field.
const validateForm = (values) => {
const errors = {};
errors.firstname = values.firstname.length >= 3;
errors.lastname = values.lastname.length >= 3;
errors.email = values.email.length >= 3;
return errors;
}
const SignUp = () => {
const eintraege = { firstname: '', lastname: '', email: '' };
const [formValues , setFormValues] = useState(eintraege);
const [errors, setErrors] = useState({});
const [buttonDisabled, setButtonDisabled] = useState(true);
const formChangeHandler = (event) => {
const { name, value } = event.target;
const nextValues = {...formValues, [name]: value };
setErrors(validateForm(nextValues));
};
const handleSubmit = (event) => {
event.preventDefault();
setButtonDisabled(true);
};
const btnChanged = () => {
return (Object.keys(errors).length === 0) ?
setButtonDisabled(true) :
setButtonDisabled(false) ;
};
return (
<FormBox onSubmit={handleSubmit}>
<ProfileImage />
<InputWrapper gridPosition="firstname-input">
<Input
type="text"
name='firstname'
value={formValues.firstname}
placeholder='Vorname'
hasError={errors.firstname === false}
onChangeHandler={formChangeHandler}
/>
<Error errors={errors} name="firstname" />
</InputWrapper>
<Button className="btn" disabled={buttonDisabled}/>
</FormBox>
);
}

Related

Can't update defaultValue with onChange React.js Firebase

I'm making a dynamically rendered form using map and I update all the values into a dictionary. However, once I update the values, I storage them into Firebase and when I submit the form, I need to display what I storage as the input default values.
const [local, setLocal] = useState([]);
const [visitante, setVisitante] = useState([]);
const handleChangeLocal = (e, i) => {
const { value, name } = e.target;
const newState = [...local];
newState[i] = {
...newState[i],
[name]: value,
};
setLocal(newState);
};
const handleChangeVisitante = (e, i) => {
const { value, name } = e.target;
const newState = [...visitante];
newState[i] = {
...newState[i],
[name]: value,
};
setVisitante(newState);
};
// FIREBASE
const resultados = {};
for (let i = 1; i < local.length; i++) {
resultados[i] = { local: local[i], visitante: visitante[i] };
}
async function saveResults() {
const decodedToken = await firebase.auth().currentUser?.getIdTokenResult();
const uid = decodedToken?.claims?.user_id;
const db = firebase.firestore();
const quiniela = db
.collection("users")
.doc(uid)
.collection("pool")
.doc("results");
quiniela.set({
resultados: resultados,
});
router.push(`/quiniela/${uid}`);
}
<input
id={i}
type="number"
defaultValue={
userData[partido["partido"]].local[
partido["HomeTeam"]
]
}
className="w-12 border -ml-8 text-center"
placeholder="#"
name={partido["HomeTeam"]}
required
step={1}
min={0}
max={20}
onChange={(e) =>
handleChangeLocal(e, partido["partido"])
}
/>
<input
id={i}
type="number"
className="w-12 border ml-20 text-center"
placeholder="#"
defaultValue={
userData[partido["partido"]].visitante[
partido["AwayTeam"]
]
}
name={partido["AwayTeam"]}
step={1}
min={0}
max={20}
onChange={(e) =>
handleChangeVisitante(e, partido["partido"])
}
required
/>
It works when I submit data for the first time, however, onChange doesn't work once I set the defaultValues from Firebase.
What's going on? Or what should I change?
Because defaultValue cannot be updated.
Use value instead
value={
userData[partido["partido"]].local[
partido["HomeTeam"]
]
}

ReactJS form need to submit 2 times to work

const [name, setName] = useState("");
const [age, setAge] = useState("");
const initialValues = {
name: "",
age: "",
};
const [formValues, setFormValues] = useState(initialValues);
const [formErrors, setFormErrors] = useState({});
const [isSubmit, setIsSubmit] = useState(false);
const handleChange = (e) => {
const { name, value } = e.target;
setFormValues({ ...formValues, [name]: value });
};
const handleSubmit = (e) => {
setFormErrors(validate(formValues));
setIsSubmit(true);
};
const validate = (values) => {
const errors = {};
if (!values.name) {
errors.name = "Name is required";
}
if (!values.age) {
errors.age= "Age is required";
}
return errors;
};
const userCreate = async () => {
await api.post("/createuser", {
name,
age,
});
};
return (
<div class="container">
<Form
onSubmit={
Object.keys(formErrors).length === 0 && isSubmit
? userCreate
: handleSubmit
}
>
<Form.Field>
<label>Name</label>
<input
name="name"
onChange={(e) => {
setName(e.target.value);
handleChange(e);
}}
values={formValues.name}
/>
<span className="error-message">{formErrors.name}</span>
</Form.Field>
<Form.Field>
<label>Age</label>
<input
name="age"
onChange={(e) => {
setAge(e.target.value);
handleChange(e);
}}
values={formValues.age}
/>
<p className="error-message">{formErrors.age}</p>
</Form.Field>
<Button type="submit">Submit</Button>
</Form>
</div>
);
I'm trying to use axios to do POST method for creating user.
I got everything works fine but there's one small problem but I don't know how to fix.
The problem is that I always need to submit the form 2 times to make the POST request. There's nothing happen in the first submit, but it will work in the second submit.
Does anyone know what's wrong with my code?
Edited
According to #DBS solution.
I'm trying to follow the steps but now the form can't submit anymore. Can someone let me know if I missed something?
const [name, setName] = useState("");
const [age, setAge] = useState("");
const initialValues = {
name: "",
age: "",
};
const [formValues, setFormValues] = useState(initialValues);
const [formErrors, setFormErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const handleChange = (e) => {
const { name, value } = e.target;
setFormValues({ ...formValues, [name]: value });
};
const handleSubmit = (e) => {
if (!Object.keys(formErrors).length && !isSubmitting) {
setFormErrors(validate(formValues));
} else {
userCreate();
setisSubmitting(true);
}
};
const validate = (values) => {
const errors = {};
if (!values.name) {
errors.name = "Name is required";
}
if (!values.age) {
errors.age= "Age is required";
}
return errors;
};
const userCreate = async () => {
await api.post("/createuser", {
name,
age,
});
};
return (
<div class="container">
<Form
onSubmit={handleSubmit}
>
<Form.Field>
<label>Name</label>
<input
name="name"
onChange={(e) => {
setName(e.target.value);
handleChange(e);
}}
values={formValues.name}
/>
<span className="error-message">{formErrors.name}</span>
</Form.Field>
<Form.Field>
<label>Age</label>
<input
name="age"
onChange={(e) => {
setAge(e.target.value);
handleChange(e);
}}
values={formValues.age}
/>
<p className="error-message">{formErrors.age}</p>
<
The issue here is your isSubmit, it is required to be true for userCreate to be called:
onSubmit={
Object.keys(formErrors).length === 0 && isSubmit
? userCreate
: handleSubmit
}
But it starts as false:
const [isSubmit, setIsSubmit] = useState(false);
And is only ever updated when handleSubmit is called (which, confusingly, is only called when the validation fails)
So your current code does this:
isSubmit is false
Submit is clicked, handleSubmit is called and isSubmit is set to true
Submit is clicked again, now isSubmit is true it will call userCreate
To solve this, there are a few different approaches, but I would:
Move all the submit handler logic into onSubmit={handleSubmit} (To keep things clear)
Inside there, do your error length check (0 error) and isSubmit (Which I would probably rename to isSubmitting for clarity, and make sure it's false) (E.g. !Object.keys(formErrors).length && !isSubmitting)
If there are errors, show the appropriate message (Leaving isSubmitting as false)
If not, call userCreate (And set isSubmitting to true)
Lastly, if this can be submitted multiple times, add an effect/callback/then to reset isSubmitting once the call is complete.
Are you using the isSubmitting flag for something? if not below might be work for you.
If there is no error, calling the create method
const handleSubmit = (e) => {
setFormErrors(validate(formValues));
if(Object.keys(formErrors).length === 0) {
userCreate();
}
};
if isSubmitting is used to check the submit or create in progress
const handleSubmit = (e) => {
setFormErrors(validate(formValues));
if(Object.keys(formErrors).length === 0) {
setIsSubmitting(true);
userCreate();
}
};
The flag isSubmitting should be set as false on API is success or failed
setIsSubmitting(false)

For multi-page forms where parent has to call validate() on child, how to manage state?

To provide some context, I am working on building a multi-page form where each page is its own component that should re-render itself in response to (valid/invalid) user input and prevent the form to move to the next page for invalid inputs on current page. Since there is no two-way binding in React, I leveraged a shared context provider between parent-child and used a custom hook to access validation logic. In order to perform the validation checks from the parent I attach a reference to a function which I call inside the child by sending it via props. Each time the parent has to move to next page it simply calls the function that is pointed to by this reference.
Shared context:
class Role {
id: string = '';
description: string = '';
tenure: string = '';
}
class Person {
name: string = '';
age: string = '';
roles: Role[] = [];
}
export const SharedContextProvider: React.FC = ({children}) => {
const [person, setPerson] = useState<Person>(new Person('', ''));
const validateName = () => {
let isValid = person.name !== '';
return {isValid: () => isValid, error: () => isValid ? '' : 'Invalid Name'};
};
...; // other validation methods here skipped
const isValidSection = (errorSetters: Map<FIELDS, (error: string) => void>, validatorHelper: Map<FIELDS, Helper>) => {
let isValidSection = true;
errorSetters.forEach((setError, field) => {
let validation = validatorHelper.get(field);
if (!validation) {
throw new Error('validation not defined!');
}
let isValidField = validation.isValid(); // check if field is valid
isValidSection = isValidSection && isValidField;
let error = validation?.error() || '';
console.log('Validating', field, 'isValid:', isValidField, 'error:', error);
let doSth = errorSetters.get(field)!!;
doSth(error); // debugging
});
return isValidSection;
}
const personalDetailsValidator = (errorSetters: Map<FIELDS, (error: string) => void>) => {
const validatorHelper = new Map<FIELDS, Helper>(
[
[FIELDS.NAME, validateName()],
[FIELDS.AGE, validateAge()],
]
);
return {isValidSection: () => isValidSection(errorSetters, validatorHelper)};
};
const professionalDetailsValidator = (role: Role, errorSetters: Map<FIELDS, (error: string) => void>) => {
const validatorHelper = new Map<FIELDS, Helper>(
[
[FIELDS.DESCRIPTION, validateRoleDescription(role)],
[FIELDS.TENURE, validateTenure(role)],
]
);
return {isValidSection: () => isValidSection(errorSetters, validatorHelper)};
};
const data: SharedContextValue = {
person,
personalDetailsValidator,
professionalDetailsValidator,
setPerson
};
return <SharedContext.Provider value={data}>{children}</SharedContext.Provider>
}
const useSharedContext = () => {
const context = useContext(SharedContext);
if (context === undefined) {
throw new Error('Cannot be undefined');
}
return context;
}
Parent
const App = () => {
const [
activeStepIndex, // controls page on the form
setActiveStepIndex
] = React.useState(0);
let isCurrentSectionValid: () => boolean; // reference to function
const validationHandler = (validateSection: () => boolean) => {
isCurrentSectionValid = validateSection;
}
return (
<Wizard
i18nStrings={{...}}
onNavigate={({detail}) => {
let isValidSection = isCurrentSectionValid();
console.log('[isValidSection]', isValidSection);
if (isValidSection) {
setActiveStepIndex(detail.requestedStepIndex)
}
}
}
activeStepIndex={activeStepIndex}
steps={[
{
content: <PersonalDetails validationHandler={validationHandler}/>
},
{
title: "Completed",
content: <Final validationHandler={validationHandler}/>,
isOptional: true
},
]}
/>
);
}
Child1
const PersonalDetails: React.FC<PersonalProps> = ({validationHandler}) => {
const {person, personalDetailsValidator, setPerson} = useSharedContext();
const [name, setName] = useState(person.name || '');
const [age, setAge] = useState(person.age || '');
const [nameErrorText, setNameErrorText] = useState<string>('');
const [ageErrorText, setAgeErrorText] = useState<string>('');
useEffect(() => {
setPerson(new Person(name, age));
}, [name, age]);
const validator = personalDetailsValidator(new Map<FIELDS, (error: string) => void>([
[FIELDS.NAME, setNameErrorText],
[FIELDS.AGE, setAgeErrorText],
]));
// store validation state for each child
const rolesValidators: Map<string, () => boolean> = new Map<string, () => boolean>();
const roleValidationHandler = ((validateSection: () => boolean, id: string) => {
rolesValidators.set(id, validateSection);
});
validationHandler(() => {
let isValidSection = validator.isValidSection();
let areValidRoles = Array.from(rolesValidators.values()).map(item => item())
.reduce((i, j) => i && j, true);
console.log('isValidSection', isValidSection, 'areValidRoles', areValidRoles);
return isValidSection && areValidRoles;
});
return (
<Container
header={
<Header variant="h2">
Personal Info
</Header>
}
>
<SpaceBetween direction="vertical" size="l">
<FormField label="Name" errorText={nameErrorText}>
<Input value={name} placeholder={'Enter Name'} onChange={({detail}) => {
setName(detail.value);
}}/>
</FormField>
<FormField label="Age" errorText={ageErrorText}>
<Input value={age} placeholder={'Enter Age'}
onChange={({detail}) => {
setAge(detail.value);
}}
/>
</FormField>
{person.roles.map((role, index) =>
<ProfessionalDetails key={role.id} validationHandler={roleValidationHandler} role={role}/>)}
</SpaceBetween>
</Container>
);
}
Child2:
const ProfessionalDetails: React.FC<ProfessionalProps> = ({validationHandler, role}) => {
const [description, setDescription] = useState(role.description || '');
const [tenure, setTenure] = useState(role.tenure || '');
const [descriptionErrorText, setDescriptionErrorText] = useState<string>();
const [tenureErrorText, setTenureErrorText] = useState<string>();
const {professionalDetailsValidator} = useSharedContext();
const validator = professionalDetailsValidator(role, new Map<FIELDS, (error: string) => void>([
[FIELDS.DESCRIPTION, setDescriptionErrorText],
[FIELDS.TENURE, setTenureErrorText],
]));
validationHandler(() => {
return validator.isValidSection();
}, role.id);
useEffect(() => {
role.description = description;
role.tenure = tenure;
console.log('Updating role...', JSON.stringify(role));
}, [role]);
return (
<Container
header={
<Header variant="h2">
Professional Info
</Header>
}
>
<SpaceBetween direction="vertical" size="l">
<FormField label="Description" errorText={descriptionErrorText}>
<Input value={description} placeholder={'Enter Occupation'}
onChange={event => setDescription(event.detail.value)}/>
</FormField>
<FormField label="Tenure" errorText={tenureErrorText}>
<Input value={tenure} placeholder={'Enter Hobby'}
onChange={event => setTenure(event.detail.value)}/>
</FormField>
</SpaceBetween>
</Container>
);
}
Child1,Child2 is validated as expected in isolation. But for list of child2 components if previous states capture an error (for empty input) then the state is not reset when the error is rectified and the errors are retained preventing moving to the next page.
I had two questions:
Is this a sustainable approach to validate forms with deep nested components?
What are good patterns for parent-child communication in these situations?
Note: I cannot use Redux due to my company constraints. It has to be done via React Context/Hooks.

React set default value from Select List after load

I have a form that has a select list of countries and a cascading select list of regions. When a new country is selected, the corresponding regions are loaded. I am trying to set the value for the region after the the select list loads as the first value in the list. On page render I am loading the country select list here:
useEffect(() => {
fetchCountries();
}, []);
When a new country is selected, I am triggering the corresponding regions to be loaded here:
useEffect(() => {
fetchRegions();
regionData.length && setInput({...input, ["region"]: regionData[0].value})
}, [input["country"]]);
This is also where I am trying to set the default region value as the first item in the list, but the state is not being updated. Where have I gone wrong? More code below, with non-relevant code removed for brevity.
export default function Signup() {
const initialInput: SignupRequest = {
country: "US",
region: ""
};
const initialErrors: ValidationError = {
country: "",
region: ""
};
const [input, setInput] = useState<SignupRequest>(initialInput);
const [errors, setErrors] = useState<ValidationError>(initialErrors);
const [countryData, setCountryData] = useState<SelectListModel["data"]>([]);
const [countryLoaded, setCountryLoaded] = useState<boolean>(false);
const [regionData, setRegionData] = useState<SelectListModel["data"]>([]);
const [regionLoaded, setRegionLoaded] = useState<boolean>(false);
useEffect(() => {
fetchCountries();
}, []);
useEffect(() => {
fetchRegions();
regionData.length && setInput({...input, ["region"]: regionData[0].value})
}, [input["country"]]);
function handleSelectChange(event: React.ChangeEvent<HTMLSelectElement>) {
const { name, value } = event.target;
setInput({ ...input, [name]: value });
}
function handleBlur(event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) {
const { name, value } = event.target;
validateInput(name, value);
}
function validateInput(name: string, value: string | string[] | boolean) {
let result = ValidationService.ValidateInput(name, value);
setErrors({ ...errors, [name]: result });
}
function handleFormSubmit(event: React.FormEvent<HTMLFormElement>) {
// process form
}
async function fetchCountries() {
const response = await LocationService.getAllCountries();
if (response?.ok) {
const responseData = await response.json() as CountryResponse[];
const countries = LocationService.maptoCountrySelectList(responseData);
setCountryData(countries);
setCountryLoaded(true);
}
}
async function fetchRegions() {
const response = await LocationService.getRegionsByCountryCode(input["country"]);
if (response?.ok) {
const responseData = await response.json() as RegionResponse[];
const regions = LocationService.maptoRegionSelectList(responseData);
setRegionData(regions);
setRegionLoaded(true);
}
}
return (
<div className="account-content">
<form onSubmit={handleFormSubmit}>
<FormGroup addClass='form-group'>
<Label label='country' title='Country' />
{!countryLoaded
? <LoadingSpinner text="Loading..." />
: <SelectList data={countryData} name='country' value={input["country"]} addClass={countryLoaded && errors["country"] ? 'is-invalid' : ''} onChange={handleSelectChange} onBlur={handleBlur} />}
<FormError message={errors["country"]} />
</FormGroup>
<FormGroup addClass='form-group'>
<Label label='region' title='State/Region/Province' />
{!regionLoaded
? <LoadingSpinner text="Loading..." />
: <SelectList data={regionData} name='region' value={input["region"]} addClass={regionLoaded && errors["region"] ? 'is-invalid' : ''} onChange={handleSelectChange} onBlur={handleBlur} />}
<FormError message={errors["region"]} />
</FormGroup>
<Button type='submit' value='Sign Up' addClass='btn-mdBlue' />
</form>
</div>
)
}
You need to setInput for region inside your fetchRegions function because setState is not synchonous so when you setRegion, and right after you setInput, region is still empty, on next render region gets filled with your previous setRegion but useEffect has already been run
const fetchRegions = async () => {
const regions = await // fetchsomething
setRegions(regions);
setInput({ ...input, region: regions[0].value });
}

ReactJS form submission using UseState

So I've Managed to made an html form for my react app. The problem is that I cannot output on my console log the inputs on my form. it just shows me this:
Console Log Output Pic
Here is my code snippet:
import { useState } from "react";
const InputForm = (props) => {
const [inputData, setInputData] = useState(
{
enteredFName: "",
enteredLName: "",
enteredEmail: "",
enteredEid: "",
enteredBirthday: "",
},
[]
);
//First Name Validation
const [enteredFName, setEnteredFName] = useState("");
const [enteredFNameTouch, setEnteredFNameTouch] = useState(false);
const enteredFNameFilled = enteredFName.trim() !== "";
const enteredFNameNotFilled = !enteredFNameFilled && enteredFNameTouch;
const enteredFNameValid = /^[A-Za-z\s]+$/.test(enteredFName);
const enteredFNameInvalid = !enteredFNameValid && enteredFNameNotFilled;
const fNameChangeHandler = (event) => {
setEnteredFName(event.target.value);
};
const fNameBlurHandler = () => {
setEnteredFNameTouch(true);
};
//Last Name Validation
const [enteredLName, setEnteredLName] = useState("");
const [enteredLNameTouch, setEnteredLNameTouch] = useState(false);
const enteredLNameFilled = enteredLName.trim() !== "";
const enteredLNameNotFilled = !enteredFNameFilled && enteredLNameTouch;
const enteredLNameValid = /^[A-Za-z\s]+$/.test(enteredLName);
const enteredLNameInvalid = !enteredLNameValid && enteredLNameNotFilled;
const lNameChangeHandler = (event) => {
setEnteredLName(event.target.value);
};
const lNameBlurHandler = () => {
setEnteredLNameTouch(true);
};
//EmailValidation
const [enteredEmail, setEnteredEmail] = useState("");
const [enteredEmailTouch, setEnteredEmailTouch] = useState(false);
const enteredEmailFilled = enteredEmail.trim() !== "";
const enteredEmailNotFilled = !enteredEmailFilled && enteredEmailTouch;
const enteredEmailValid = enteredEmail.includes("#");
const enteredEmailInvalid = !enteredEmailValid && enteredEmailNotFilled;
const emailChangeHandler = (event) => {
setEnteredEmail(event.target.value);
};
const emailBlurHandler = () => {
setEnteredEmailTouch(true);
};
//EIDValidation
const [enteredEid, setEnteredEid] = useState("");
const [enteredEidTouch, setEnteredEidTouch] = useState(false);
const enteredEidFilled = enteredEid.trim() !== "";
const enteredEidNotFilled = !enteredEidFilled && enteredEidTouch;
const eidChangeHandler = (event) => {
setEnteredEid(event.target.value);
};
const eidBlurHandler = () => {
setEnteredEidTouch(true);
};
//Birthday Validation
const [enteredBirthday, setEnteredBirthday] = useState("");
const [enteredBirthdayTouch, setEnteredBirthdayTouch] = useState(false);
const enteredBirthdayFilled = enteredBirthday.trim() !== "";
const enteredBirthdayNotFilled =
!enteredBirthdayFilled && enteredBirthdayTouch;
const birthdayChangeHandler = (event) => {
setEnteredBirthday(event.target.value);
};
const birthdayBlurHandler = () => {
setEnteredBirthdayTouch(true);
};
let formValid = false;
if (
enteredFNameFilled &&
enteredLNameFilled &&
enteredEmailFilled &&
enteredEidFilled &&
enteredBirthdayFilled
) {
formValid = true;
}
const formSubmitHandler = (event) => {
event.preventDefault();
if (!enteredFNameValid || !enteredLNameValid) {
alert("First Name and Last Name accepts letters only.");
return;
}
console.log(inputData);
setEnteredFName("");
setEnteredFNameTouch(false);
setEnteredLName("");
setEnteredLNameTouch(false);
setEnteredEmail("");
setEnteredEmailTouch(false);
setEnteredEid("");
setEnteredEidTouch(false);
setEnteredBirthday("");
setEnteredBirthdayTouch(false);
};
return (
<form onSubmit={formSubmitHandler}>
<div>
<h1>Please Enter your details below</h1>
</div>
<div className="control-group">
<div>
<label>First Name</label>
<input
type="text"
required
id="fName"
onChange={fNameChangeHandler}
onBlur={fNameBlurHandler}
value={enteredFName}
/>
{enteredFNameInvalid && <p>First Name is required.</p>}
</div>
<div>
<label>Last Name</label>
<input
type="text"
required
id="lName"
onChange={lNameChangeHandler}
onBlur={lNameBlurHandler}
value={enteredLName}
/>
{enteredLNameInvalid && <p>Last Name is required.</p>}
</div>
</div>
<div>
<label>Email</label>
<input
type="email"
required
id="email"
onChange={emailChangeHandler}
onBlur={emailBlurHandler}
value={enteredEmail}
/>
{enteredEmailInvalid && <p>Email is required.</p>}
</div>
<div>
<label>EID</label>
<input
type="number"
required
min="1"
step="1"
id="eid"
onChange={eidChangeHandler}
onBlur={eidBlurHandler}
value={enteredEid}
/>
{enteredEidNotFilled && <p>EID is required.</p>}
</div>
<div>
<label>Birthday</label>
<input
type="date"
required
id="birthday"
onChange={birthdayChangeHandler}
onBlur={birthdayBlurHandler}
value={enteredBirthday}
/>
{enteredBirthdayNotFilled && <p>Birthday is required.</p>}
</div>
<div>
<button type="submit" disabled={!formValid}>
Submit
</button>
</div>
</form>
);
};
export default InputForm;
How do I utilize the setInputData for my overall form submission? because I don't know where to put it on the code.
I don't think you need the inputData state, since all your values are already saved in other state variables.
Can you try to console log the following in your formSubmitHandler:
console.log({
enteredFName,
enteredLName,
enteredEmail,
enteredEid,
enteredBirthday,
})
If you insist on keeping the separate state object for submitted values, you can just replace the console.log by setInputData in formSubmitHandler:
setInputData({
enteredFName,
enteredLName,
enteredEmail,
enteredEid,
enteredBirthday,
}
First of all , If you have multi form in your react project, try to use your own hook or use react form hook or formik to make it easier and lower code , its better to get object from Form and pass it like this :
setInputData(data)
If is not possible , set each property in setInputData, and if you have a lot of state , try to write dynamic handler function instead of function for each item , like this :
function handle(type,value){
useState(prev => {
...prev,
[type]:value
})
}

Resources