Problem I'm trying to solve: Form validation for an app built in React that takes in user input and generates a CV. This is for learning purposes and part of The Odin Project curriculum.
How I'm trying to solve form validation: I have my project organized with a large formData object set as state in App.js and I'm sharing that state to all child components via useContext. For validation, I have given each piece of CV data 2 properties in my formData object. Example below:
{firstname: '', firstNameValid: true}
I am trying to write a function (see attached code) that sets the validity of each propertyValid and set it to false.
What I expect: When a field is invalid (like firstName), it sets firstNameValid: false
when I run the invalidateField('firstName')
function.
What happens instead: Logging the formData reveals that firstNameValid
is still set to true
.
What I have tried: As seen in the attatched code, I am trying to make a copy of my formData object, set only the value I want, and then just manually set it using setFormData(formCopy)
. However, when I log them together, I see that while formCopy looks like what I want it to be, the formData in state still has not changed. I am updating state just fine from my grandchildren components, but I'm unable to do it here and I don't understand why.
//my object declared in state
const [formData, setFormData] = React.useState({
firstName: '',
lastName: '',
email: '',
firstNameValid: true,
lastNameValid: true,
emailValid: true
//a lot more than this but you get the idea
});
//function in question that is not working
function invalidateField(string){
//takes the name of the key as a string
let key = `${string}Valid`;
let value = false;
let formCopy = {...formData};
formCopy[key] = value;
setFormData(formCopy);
console.log(formCopy, formData);
}
//function I'm writing to check validity of input fields
//called by button click elsewhere in code
function formIsValid(formData){
let validity = true;
if(formData.firstName.length < 1){ //firstName = '' (field is empty)
console.log('your first name is too short');
invalidateField('firstName');
validity = false;
}
return validity;
}
//context then passed to child components in the return statement.
CodePudding user response:
The setFormData method is an async function. It takes a while until the state is updated. You console.log right after calling setFormData, thats why it looks as if your setState didnt work properly when it just needs a little more time to complete.
Above your invalidateField function you could write an useEffect to print out when your state has changed:
import { useEffect } from "react";
useEffect(() => {
console.log(formData);
}, [formData]);
This will execute the console.log as soon as formData has changed.