Justin
Justin

Reputation: 77

how to multiple validation in form with react hook

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

Answers (3)

Dmytro Krasnikov
Dmytro Krasnikov

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

sanat choubey
sanat choubey

Reputation: 42

from where formState is coming? and you can use usereducer or react-hook-form library for better approch

Upvotes: 0

Netanel Vaknin
Netanel Vaknin

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

Related Questions