Calling custom hook setState from inside form submission handler does not update state
P粉976488015
P粉976488015 2023-09-16 11:39:44
0
1
953

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粉976488015
P粉976488015

reply all(1)
P粉057869348

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.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template