Home > Blockchain >  React cannot set variable inside onClick function
React cannot set variable inside onClick function

Time:03-01

I am trying to set a variable inside an onClick event. I am setting the error messages into the variable.

const handleEdit = (e) => {
        e.preventDefault();

         if (edit_user.email == "") {
             setEditUserError({ email: "Please enter an email!" })
        }

        if (edit_user.company == "") {
           setEditUserError({ ...edit_user_error, company: "Please enter company!" })
       }

And I am showing the error in the form like <span className="text-danger">{edit_user_error.company}</span>

The problem is that when all the fields are empty and when I click the button only the last message is shown. When I make one field empty, and then click the submit button it is working correctly. I tried console.log(edit_user_error) but it is showing empty. What am I doing wrong? Please help

CodePudding user response:

This is because of batched state updates. React will try to reduce the renders by minimizing the state updates. You can use functional state update to fix this:

if (edit_user.email == "") {
  setEditUserError({ email: "Please enter an email!" });
}

if (edit_user.company == "") {
  // this callback gets executed only when previous state updates are done
  setEditUserError((prev) => ({ ...prev, company: "Please enter company!" }));
}

To clear the errors when fields are valid:

const getErrors = () => {
  return {
    ...(!edit_user.email ? { email: "Please enter an email!" } : {}),
    ...(!edit_user.company ? { company: "Please enter company!" } : {}),
  };
};

const handleEdit = (e) => {
  e.preventDefault();

  setEditUserError(getErrors());
};

CodePudding user response:

React state updates are async, which means they won't run right away. So when running multiple setState to the same state, you can't expect the state from the first setState call to be update it before the second setState call happens.

In short, React is ignoring your earlier setState calls because they happen one after another.

The solution is to put the update into a single call:

    const handleEdit = (e) => {
        e.preventDefault();
         
        let errors = {};

         if (edit_user.email == "") {
             errors.email = "Please enter an email!"
        }

        if (edit_user.company == "") {
           errors.company = "Please enter company!"
       }

      // and then we call state with all the values, only once
      setEditUserError(errors);

  • Related