не работает проверка формы с помощью react-hook useFormInput()

#reactjs #validation #react-hooks

#reactjs #проверка #реагирующие крючки

Вопрос:

Ссылка на изолированную среду кодаhttps://stackblitz.com/edit/react-cdv6mx?devtoolsheight=33amp;file=src/ResetPassword.js

ОБЪЯСНЕНИЕ: Когда пользователь вводит неверные данные, сервер отправляет ошибку 400: bad request с сообщением, которое можно увидеть на Response tab вкладке сети. Цель состоит в том, чтобы проверить поля формы перед отправкой формы и отобразить сообщение об ошибке, если введены неправильные поля. Кроме того, предполагается отключить сброс кнопки до тех пор, пока поля формы не будут соответствовать критериям. Таким образом, это предотвратит случайную отправку пользователем наполовину введенных полей.

У меня есть функциональный компонент, в котором у меня есть простая форма.

ПРОБЛЕМА: я вызываю validatForm() метод onChange . Метод должен сначала проверить, совпадают ли NewPassword и confirmPassword и соответствуют ли они правилам (требованиям) паролей, и, если true, только после этого отправлять данные.

ОБНОВЛЕННЫЙ КОД НАХОДИТСЯ В ССЫЛКЕ STACKBLITZ ВЫШЕ.

Я использую useFormInput() , как показано ниже

   const email = useFormInput("");
  const newPassword = useFormInput("");
  const confirmPassword = useFormInput("");
  

и я написал useFormInput() метод

 const useFormInput = (initialValue) => {
  const [value, setValue] = useState(initialValue);

  const handleChange = (e) => {
    setValue(e.target.value);
  };
  return {
    value,
    onChange: handleChange,
  };
};
  

и validateForm() метод, и я передаю его своему <button/>

 /*  Your password must contain at least one capital letter, one
      *number and one lowercase letter, and it must contain at least 8
      *characters*/


const validateForm = (event) => {
    let pass = event.target.value;
    let reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/;
    let test = reg.test(pass);
    if (test) {
      this.setState({ value: event.target.value });
    } else {
      alert("password validation unsuccessful. Please try again.");
      return;
    }
  };
  

и в render()

 <FormGroup row>
            <Label for="Email" sm={2}>
              Email
            </Label>
            <Col sm={4}>
              <Input
                type="email"
                name="email"
                id="Email"
                
                {...email}
              />
            </Col>
          </FormGroup>
          <FormGroup row>
            <Label for="newPassword" sm={2}>
              New Password
            </Label>
            <Col sm={4}>
              <Input
                type="password"
                name="password"
                id="newPassword"
                
                {...newPassword}
              />
            </Col>
          </FormGroup>
          <FormGroup row>
            <Label for="confirmPassword" sm={2}>
              Confirm Password
            </Label>
            <Col sm={4}>
              <Input
                type="password"
                name="confirmPassword"
                id="confirmPassword"
                
                {...confirmPassword}
              />
            </Col>
          </FormGroup>
          <div className="form-actions">
            {error amp;amp; (
              <>
                <small style={{ color: "red" }}>{error}</small>
                <br />
              </>
            )}
            <br />

            <Col lg={{ offset: 2 }} sm={{ size: 1 }}>
              <Button
                className="mail-reset-btn"
                block
                type="submit"
                value={loading ? "Loading..." : "Login"}
                onClick={handleReset}
                disabled={!validateForm}
              >
                Reset
              </Button>
            </Col>
          </div>
        </Form>
  

Комментарии:

1. this.setState ?

2. Вы disabled={!validateForm} нажали кнопку отправки, validateForm не вызывается. Я также не понимаю, почему вы смешали кнопки отправки и сброса.

3. для disabled : идея состоит в том, чтобы отключить кнопку сброса, если поля формы недопустимы. для onclick при сбросе: это ошибка. Я забыл удалить его. Я намерен использовать onSubmit

4. @SakoBu Извините, я не понимаю. пожалуйста, уточните

5. ResetPassword это функциональный компонент, поэтому вызов this.setState полностью недопустим. Когда вы пытаетесь проверить поля формы? При отправке?

Ответ №1:

Обновите свой, validateForm чтобы удалить поля пароля из события формы onSubmit . Создайте errors объект для отслеживания ошибок в полях. Если errors объект пуст, то проверка проходит, в противном случае устанавливается состояние ошибки.

 const validateForm = event => {
  event.preventDefault();

  const { confirmPassword, newPassword } = event.target;
  const errors = {};

  const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/;

  if (!regex.test(newPassword.value)) {
    errors.requirementUnmet = "New password does not meet requirements.";
  }

  if (newPassword.value !== confirmPassword.value) {
    errors.passwordMismatch = "Entered passwords do not match.";
  }

  if (!Object.keys(errors).length) {
    alert("password validation successful.");
    setError(null);
    return;
  }

  setError(errors);
};
  

Прикрепите validateForm к onSubmit дескриптору формы.

 <Form onSubmit={validateForm}>
  

Убедитесь, что у вас есть кнопка type =»отправить» в форме.

 <Button
  className="mail-submit-btn"
  block
  type="submit"
  value={loading ? "Loading..." : "Login"}
>
  Submit
</Button>
  

Обновлен stackblitz (хотя у меня нет учетной записи, поэтому копирую обновленный код ниже.)

Примечание: Я просто JSON.stringify(error) исправил ошибку для простоты, но вы захотите отобразить это более изящно.

Весь ResetPassword.js

 import React, { useState } from "react";
import {
  Button,
  Form,
  FormGroup,
  Input,
  Col,
  Label,
  Modal,
  ModalHeader,
  ModalBody,
  ModalFooter
} from "reactstrap";

const useFormInput = initialValue => {
  const [value, setValue] = useState(initialValue);

  const handleChange = e => {
    setValue(e.target.value);
  };
  return {
    value,
    onChange: handleChange
  };
};

const ResetPassword = props => {
  // form inputs
  const email = useFormInput("");
  const newPassword = useFormInput("");
  const confirmPassword = useFormInput("");
  // using hooks
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const [modal, setModal] = useState(false);

  const toggle = () => setModal(!modal);

  const validateForm = event => {
    event.preventDefault();

    const { confirmPassword, newPassword } = event.target;
    const errors = {};

    const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/;

    if (!regex.test(newPassword.value)) {
      errors.requirementUnmet = "New password does not meet requirements.";
    }

    if (newPassword.value !== confirmPassword.value) {
      errors.passwordMismatch = "Entered passwords do not match.";
    }

    if (!Object.keys(errors).length) {
      alert("password validation successful.");
      setError(null);
      return;
    }

    setError(errors);
  };

  const handleReset = e => {
    e.preventDefault();
    setError(null);
    setLoading(true);
    // some unrelated redux code
  };

  return (
    <div className="mail-reset" id="forgotPassword">
      <div className="mail-reset-content">
        <Form onSubmit={validateForm}>
          <h3 className="form-title">Enter Information</h3>

          <FormGroup row>
            <Label for="Email" sm={2}>
              Email
            </Label>
            <Col sm={4}>
              <Input
                type="email"
                name="email"
                id="Email"
                placeholder="Email"
                aria-label="email address"
                aria-describedby="email address"
                aria-invalid="false"
                {...email}
              />
            </Col>
          </FormGroup>
          <FormGroup row>
            <Label for="newPassword" sm={2}>
              New Password
            </Label>
            <Col sm={4}>
              <Input
                type="password"
                name="password"
                id="newPassword"
                placeholder="New Password"
                aria-label="new password"
                aria-describedby="new password"
                aria-invalid="false"
                {...newPassword}
              />
            </Col>
          </FormGroup>
          <FormGroup row>
            <Label for="confirmPassword" sm={2}>
              Confirm Password
            </Label>
            <Col sm={4}>
              <Input
                type="password"
                name="confirmPassword"
                id="confirmPassword"
                placeholder="Confirm Password"
                aria-label="new password"
                aria-describedby="new password"
                aria-invalid="false"
                {...confirmPassword}
              />
            </Col>
          </FormGroup>

          <div className="modal-wrapper">
            <Col sm={{ size: 4, offset: 2 }}>
              <Button onClick={toggle} className="passwordReqBtn">
                Password Requirements
              </Button>
            </Col>
            <Modal isOpen={modal} toggle={toggle} className="mail-reset-modal">
              <ModalHeader toggle={toggle}>Password Requirements</ModalHeader>
              <ModalBody>
                Your password must contain at least one capital letter, one
                number and one lowercase letter, and it must contain at least 8
                characters
              </ModalBody>
              <ModalFooter>
                <Button onClick={toggle} className="btn-modal pull-right">
                  OK
                </Button>{" "}
              </ModalFooter>
            </Modal>
          </div>

          <div className="form-actions">
            {error amp;amp; (
              <>
                <small style={{ color: "red" }}>{JSON.stringify(error)}</small>
                <br />
              </>
            )}
            <br />

            <Col lg={{ offset: 2 }} sm={{ size: 1 }}>
              <Button
                className="mail-reset-btn"
                block
                type="submit"
                value={loading ? "Loading..." : "Login"}
              >
                Submit
              </Button>
              <Button
                className="mail-reset-btn"
                block
                type="reset"
                value={loading ? "Loading..." : "Login"}
                onClick={handleReset}
              >
                Reset
              </Button>
            </Col>
          </div>
        </Form>
      </div>
    </div>
  );
};

export default ResetPassword;
  

Комментарии:

1. по какой-то причине form-actions не выполняется рендеринг. Я прикрепил изображение DOM imgur.com/a/DQoW7Z7

2. @NaumanTanwir Странно, там должны быть хотя бы Col и Button , верно? Это в вашем stackblitz или на компьютере разработчика на localhost (или другом)?

3. @NaumanTanwir Я ничего не менял в своем решении, но в вашем stackblitz handleReset есть обработчик onClick для кнопки сброса, и он устраняет ошибки путем вызова setError(null); . Какая ошибка будет / может отображаться при сбросе формы?

4. @NaumanTanwir В основном мое мнение, но это ужасная идея. Отправка и сброс — это по сути очень разные действия. Вы просто хотите, чтобы форма сбрасывалась при отправке? Если пользователь частично вводит данные и нажимает эту кнопку, вы сбрасываете форму или отправляете ее? Видите, насколько это запутанно? Только с точки зрения доступности это логистический кошмар.

5. @NaumanTanwir Ранее вы говорили, что хотите, чтобы проверка выполнялась при отправке формы, но это больше похоже на то, что вы хотите, чтобы проверка формы выполнялась при размытии (или изменении) полей. Уже поздно, и я должен идти, но я могу взглянуть на ваш обновленный stackblitz позже.