Reputation: 77
I have a useState problem, I am trying to add an object in the state but value errors, console.log(errors):
{name: "", description: "", price: "", category: "", image: "Image cannot be empty"}
I want all values in one object.
Hope everyone will help me because I am new. Here is my code:
const [errors, setErrors] = useState({
name: '',
description: '',
price: '',
category: '',
image: '',
});
const [formIsValid, setFormIsValid] = useState(true);
const handleValidation = () => {
//Name
if(!formState.name){
setFormIsValid(false);
setErrors({
...errors,
name: 'Name cannot be empty',
});
}
//category
if(!formCategory.category){
setFormIsValid(false);
setErrors({
...errors,
category: 'Category cannot be empty',
});
}
//Image
if(!image.image){
setFormIsValid(false);
setErrors({
...errors,
image: 'Image cannot be empty',
});
}
return formIsValid;
};
Upvotes: 0
Views: 11061
Reputation: 1004
You are trying to make state update based on your previous state. Basically the issue is following: you want to make few state updates synchronously (when few properties are not valid) and only last update is applied. So why this happen? In the code above when errors is equal to initial state and all fields are empty will happen following
setErrors({
...errors,
name: 'Name cannot be empty',
});
is the same as
setErrors({
description: '',
price: '',
category: '',
image: '',
name: 'Name cannot be empty',
});
after that you are entering another if statement and there you are performing another setState operation with the same state, and errors array gone be the same
so this
setErrors({
...errors,
category: 'Category cannot be empty',
});
will be transformed to this
setErrors({
description: '',
price: '',
category: 'Category cannot be empty',
image: '',
name: '',
});
React will schedule all the setState one after each other and as you are assigning object it will just override the last existing one and name property will be cleared. So it is two way to solve current issue if you want to use object as a state: Generate object and then execute setState one time with combined object, that contains all the changes:
const [errors, setErrors] = useState({
name: '',
description: '',
price: '',
category: '',
image: '',
});
const handleValidation = () => {
const newErrorsState = {...errors};
let formIsValid = true;
//Name
if(!formState.name){
formIsValid = false;
newErrorsState.name = 'Name cannot be empty';
}
//category
if(!formCategory.category){
formIsValid = false;
newErrorsState.category = 'Category cannot be empty';
}
//Image
if(!image.image){
formIsValid = false;
newErrorsState.image = 'Image cannot be empty';
}
if (!formIsValid) { // if any field is invalid - then we need to update our state
setFormIsValid(false);
setErrors(newErrorsState);
}
return formIsValid;
};
Second way to solve this issue is to use another way to set your state, You can use function inside of your setState handler. Inside that function you will receive the latest state as parameter and that state will have latest changes. More information can be found by the link
const [errors, setErrors] = useState({
name: '',
description: '',
price: '',
category: '',
image: '',
});
const [formIsValid, setFormIsValid] = useState(true);
const handleValidation = () => {
//Name
if(!formState.name){
setFormIsValid(false);
const updateNameFunction = (latestState) => {
return {
...latestState,
name: 'Name cannot be empty',
};
}
setErrors(updateNameFunction);
}
//category
if(!formCategory.category){
setFormIsValid(false);
setErrors((prevErrors) => {
return {
...prevErrors,
category: 'Category cannot be empty',
}
});
}
//Image
if(!image.image){
setFormIsValid(false);
setErrors((prevErrors) => {
return {
...errors,
image: 'Image cannot be empty',
};
});
}
return formIsValid;
};
Upvotes: 1
Reputation: 42
from where formState is coming? and you can use usereducer or react-hook-form library for better approch
Upvotes: 0
Reputation: 1153
Not sure what you are trying to achieve. Anyway I think you want to validate multiple fields and get their errors together. Please look at react-hook-form documentation
Every field that registered to the form will give you his errors "automatically". In addition, You can add validations in the object of the second argument of register like that :
<Input {...register("firstName", { required: true })} />
List of available validations that you can add
Hope thats help you :) Good luck!
Upvotes: 0