0

My form Submission would skip showing validation error message when submitting wrong input. How can I prevent submission when error message is present?

my code:

import React, { useState } from "react";

const App = () => {
  const [formData, setFormData] = useState({ name: "" });
  const [formError, setFormError] = useState({});
  const [isSubmit, setIsSubmit] = useState(false);
  const [formSubmitted, setFormSubmitted] = useState(false);

  const validate = () => {
    const errors = {};
    console.log("2. errors: ", errors); //<=== point 2.
    if (formData.name.length === 0) {
      errors.name = "name required";
    }
    console.log("3. errors: ", errors);  //<=== point 3.
    return errors;
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    setIsSubmit(true);
    console.log("1. formData: ", formData);  //<=== point 1.
    setFormError(validate(formData));
    console.log("4. formError: ", formError);  //<=== point 4.

    // This is true only if formError is empty object
    if (
      Object.keys(formError).length === 0 &&
      formError.constructor === Object
    ) {
      console.log("5. sending data: ", formData.name);  //<=== point 5.
      // Sending data to API here
      setIsSubmit(false);
      setFormSubmitted(true);
      return;
    }

    setIsSubmit(false);
    return;
  };

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData({ ...formData, [name]: value });
  };

  return (
    <>
      {formSubmitted ? (
        <p>Thank you</p> //<=== Thank you prhase
      ) : (
        <form onSubmit={handleSubmit}>
          <label htmlFor="name">Your name:</label>
          <input
            type="text"
            name="name"
            value={formData.name}
            onChange={handleChange}
          />
          {formError.name && <p>{formError.name}</p>}
          {isSubmit ? (
            <p>Sending...</p>
          ) : (
            <input type="submit" value="Submit" />
          )}
        </form>
      )}
    </>
  );
};

export default App;

console when submitting empty input (wrong input):

1. formData:  {name: ''}
2. errors:  {}
3. errors:  {name: 'name required'}
4. formError:  {}
5. sending data:  

console when submitting with input "test" (right input):

1. formData:  {name: 'test'}
2. errors:  {}
3. errors:  {}
4. formError:  {}
5. sending data:  test

When I submit a right input, the form would act as I wanted.

submit right input -> input validation -> no error found -> send data -> show "Thank you" phrase

But if I submit wrong input.

submit wrong input -> input validation -> error found -> append error message -> but still return empty object (to formError) -> send empty input -> show "Thank you" phrase

The problem is at point 4, the validate() function wont return the error message. On my actual file with API, while submitting wrong input it will show the error message (e.g. formError.name) (takes 1 to 2 seconds to send data to CMS) but the submission will still goes thru and show "thank you" phrase. How can I fix this? Thank you.

satudaku
  • 5
  • 2
  • The thing is, `setState` will not immediately update your states value since it is async, so the value will not be changed right after calling it (in your case, you are calling `setFormError` and accessing its value right after) – sschwei1 Apr 25 '22 at 08:23
  • That's what I'm looking after. thanks – satudaku Apr 25 '22 at 08:43

1 Answers1

0

State update doesn't happen synchronously.

You can extract the error in a variable (named errors in the example below) and do the conditional logic based on that instead of the state.

import React, { useState } from "react";

const App = () => {
  const [formData, setFormData] = useState({ name: "" });
  const [formError, setFormError] = useState({});
  const [isSubmit, setIsSubmit] = useState(false);
  const [formSubmitted, setFormSubmitted] = useState(false);

  const validate = () => {
    const errors = {};
    if (formData.name.length === 0) {
      errors.name = "name required";
    }
    return errors;
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    setIsSubmit(true);
    const errors = validate(formData); // extracting here
    setFormError(errors); // setting state using the extracted value

    // validating using the extracted value
    if (Object.keys(errors).length === 0 && errors.constructor === Object) {
      // Sending data to API here
      setIsSubmit(false);
      setFormSubmitted(true);
      return;
    }

    setIsSubmit(false);
    return;
  };

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData({ ...formData, [name]: value });
  };

  return (
    <>
      {formSubmitted ? (
        <p>Thank you</p> //<=== Thank you prhase
      ) : (
        <form onSubmit={handleSubmit}>
          <label htmlFor="name">Your name:</label>
          <input
            type="text"
            name="name"
            value={formData.name}
            onChange={handleChange}
          />
          {formError.name && <p>{formError.name}</p>}
          {isSubmit ? (
            <p>Sending...</p>
          ) : (
            <input type="submit" value="Submit" />
          )}
        </form>
      )}
    </>
  );
};

export default App;
Som Shekhar Mukherjee
  • 4,701
  • 1
  • 12
  • 28