search

Home  >  Q&A  >  body text

Calling custom hook setState from inside form submission handler does not update state

The fields in the form require me to focus on them in order to display the error message. I want the error message to appear when I click "Submit" when I haven't focused the field yet.

This is the hook (suspected to be about the later setIsTouched call):

const useInputModifed = (validationArray) => {
  const [enteredValue, setEnteredValue] = useState("");
  const [isTouched, setIsTouched] = useState(false);

  //   [{errorName:,fn:validationFn}]
  let errorArray = [];

  for (const errorEntry of validationArray) {
    if (errorEntry.isErrorFn(enteredValue)) {
      errorArray.push(errorEntry.errorName);
    }
  }

  const hasError = errorArray.length > 0 && isTouched;

  const valueChangeHandler = (event) => {
    setEnteredValue(event.target.value);
  };

  const reset = () => {
    setEnteredValue("");
    setIsTouched(false);
  };

  console.log(errorArray, isTouched);

  return {
    value: enteredValue,
    validationArray: errorArray,
    hasError,
    valueChangeHandler,
    setIsTouched,
    isTouched,
    reset,
  };
};

Here is the form handler (I used aliases for each field):

const formSubmissionHandler = (event) => {
    event.preventDefault();
    touchNameField(true);
    touchEmailField(true);


    if (nameInputHasError || emailInputHasError) {
 //console logging both fields gives false even after touching
      return;
    }
  
    if (!nameInputHasError && !emailInputHasError) {
      resetNameInput();
      resetEmailInput();
    }
  };

Taking the verification name field as an example, I click the submit button at the beginning. Currently in const hasError = errorArray.length > 0 && isTouched; the array has elements but isTouched is false because I don't have focus on the field.

Then "touchNameField(true);" comes in. I tried making hasError true but it still shows false.

The setState call is asynchronous, is that the problem? If I remove the reset call it works. But I still don't understand why nameInputError etc. are false.

P粉976488015P粉976488015441 days ago932

reply all(1)I'll reply

  • P粉057869348

    P粉0578693482023-09-17 10:21:46

    If you don't run it, I believe it's because errorArray and hasError are not reacting to changes. So it also depends on where you instantiate that hook. Without testing I would try the following:

    const useInputModifed = (validationArray) => {
      const [enteredValue, setEnteredValue] = useState("");
      const [isTouched, setIsTouched] = useState(false);
    
      const [errorArray, setErrorArray] = useState([]);
      const [hasError, setHasError] = useState(false);
    
      useEffect(() => {
        const newErrorArray = [];
        for (const errorEntry of validationArray) {
          if (errorEntry.isErrorFn(enteredValue)) {
            newErrorArray.push(errorEntry.errorName);
          }
        }
        setErrorArray(newErrorArray);
      }, [validationArray, enteredValue])
    
      useEffect(() => {
        setHasError(errorArray.length && isTouched);
      }, [errorArray, isTouched])
    
      const valueChangeHandler = (event) => {
        setEnteredValue(event.target.value);
      };
    
      const reset = () => {
        setEnteredValue("");
        setIsTouched(false);
      };
    
      console.log(errorArray, isTouched);
    
      return {
        value: enteredValue,
        validationArray: errorArray,
        hasError,
        valueChangeHandler,
        setIsTouched,
        isTouched,
        reset,
      };
    };
    

    Again, not tested and you may need some adjustments.

    reply
    0
  • Cancelreply