Q: How to handle React form errors gracefully I have a login form that works when you enter the right login/password. But if you enter the wrong login info, you get this ugly error message

I tried to handle this gracefully by setting a formErrors state and then returning whatever the error is in a well styled alert message, but I keep getting the error you see in the screenshot TypeError: Cannot read property 'length' of undefined.
It sounds like formErrors is undefined, but I don't understand why that would be. What am I doing wrong, and how can I fix this? I'd appreciate any help.
Edit: Added the code from loginUser function from app.js and api.js
UserLoginForm.js
function UserLoginForm({ loginUser }) {

  const [formData, setFormData] = useState({
    username: "",
    password: "",
  });
  const [formErrors, setFormErrors] = useState([]);
  const history = useHistory();

  console.debug(
    "UserLoginForm",
    "login=", typeof loginUser,
    "formData=", formData,
    "formErrors", formErrors,
);

  // Handle form submission 
  async function handleSubmit(evt) {
    evt.preventDefault();
    let results = await loginUser(formData);
    if (results.success) {
      history.push("/");
    } else {
      setFormErrors(results.errors);
    }
  }

  // Handle change function 
  function handleChange(evt) {
    const { name, value } = evt.target;
    setFormData(d => ({ ...d, [name]: value }));
  }

  return (
    <div className="container my-5">
      <div className="row">
        <div className="col-lg-2">

        </div>
        <div className="col-lg-10">
          <h1>User Login Form</h1>
          <div className="my-3">
            <form onSubmit={handleSubmit}>
              <div className="col-lg-9 my-2">
                <input
                  name="username"
                  className="form-control"
                  placeholder="Username"
                  value={formData.username}
                  onChange={handleChange}
                  required
                />
              </div>
              <div className="col-lg-9 my-2">
                <input
                  name="password"
                  className="form-control"
                  placeholder="Password"
                  type="password"
                  value={formData.password}
                  onChange={handleChange}
                  required
                />
              </div>

              {formErrors.length
                ? <Alert type="danger" messages={formErrors} />
                : null
              }

              <button className="btn btn-lg btn-primary my-3">
                Submit
              </button>
            </form>
          </div>
        </div>
        <div className="col-lg-2">

        </div>
      </div>
    </div>
  );
} 

Alert.js
function Alert({ type="danger", messages=[] }) {
  console.debug("Alert", "type=", type, "messages=", messages);
    return (
      <div className={`alert alert-${type}`} role="alert">
        {messages.map(error => (
          <p key={error} className="mb-0 small">
            {error}
          </p>
        ))}
      </div>
    );
}

App.js
 async function loginUser(loginData) {
    try {
      let token = await VolunteerApi.loginUser(loginData);
      setToken(token);
      return {
        success: true
      };
    } catch (err) {
      console.error("Problem with the login function", err);
      return {
        success: false, err
      };
    }
  }

api.js
static async loginUser(data) {
    let res = await this.request(`auth/login-user`, data, "post");
    return res.token;
  }


A: Your issue is that you aren't returning {errors} from loginUser function. You were returning {err} instead, hence formErrors.length was throwing an error, because formErrors was set to undefined.
You need to make sure to return what you are expecting it to. I've modified it below, though without too much information, but it'll run.
Note that you'll probably have to map from the error returned from the API to a string message.
 async function loginUser(loginData) {
    try {
      let token = await VolunteerApi.loginUser(loginData);
      setToken(token);
      return {
        success: true
      };
    } catch (err) {
      console.error("Problem with the login function", err);
      return {
        success: false, errors: [err]
      };
    }
  }

