Форма сброса начальной загрузки React после отправки

#reactjs #forms #next.js #react-bootstrap

Вопрос:

Здравствуйте, я пытаюсь настроить контактную форму с помощью начальной загрузки React в React/Next.js приложение. Как бы я сбросил форму после ее отправки? Когда я добавил дескриптор сброса, проверка больше не работала.

   // Form validation
  const [validated, setValidated] = useState(false);

  // Thank you Message
  const [thankYouMessage, setThankYouMessage] = useState(false);

  // Form submit handler
  async function handleSubmit(e) {
    e.preventDefault();
    e.stopPropagation();

    const formData = new FormData();

    Array.from(e.currentTarget.elements).forEach((field) => {
      if (!field.name) return;
      formData.append(field.name, field.value);
    });

    await fetch(
      "https://domain.tld/wp-json/contact-form-7/v1/contact-forms/1234/feedback",
      {
        body: formData,
        method: "POST",
      }
    )
      .then((response) => response.json())
      .then((response) => {
        if (response.status === "mail_sent") {
          setThankYouMessage(!thankYouMessage);
        } else if (response.status === "mail_failed") {
          alert("Message failed to send.");
        }
      });

    setValidated(true);
  }
 

Это форма:

   <div>
    <Form
      noValidate
      validated={validated}
      onSubmit={handleSubmit}
    >
      <Form.Group controlId="your-name">
        <Form.Control
          required
          type="text"
          placeholder="Your name"
          name="your-name"
        />
        <Form.Control.Feedback type="invalid">
          Please enter your name
        </Form.Control.Feedback>
      </Form.Group>
      <Form.Group controlId="your-email">
        <Form.Control
          required
          type="email"
          placeholder="Your email address"
          name="your-email"
        />
        <Form.Control.Feedback type="invalid">
          Please enter your email
        </Form.Control.Feedback>
      </Form.Group>
      <Form.Group controlId="your-message">
        <Form.Control
          as="textarea"
          cols={30}
          rows={6}
          placeholder="Write your message..."
          name="your-message"
        />
      </Form.Group>
      <Button type="submit" variant="primary" size="lg">
        Send Message
        <span></span>
      </Button>
    </Form>
    <Alert
      variant="success"
      className={thankYouMessage ? "d-block mt-3" : "d-none"}
    >
      Thank you for your message. It has been sent.
    </Alert>
  </div>
 

Я попытался настроить дескриптор сброса useRef() , но это не сработало:

   const formRef = useRef(null);
  const handleReset = () => {
    formRef.current.reset();
    setValidated(false);
  };
 

Затем в добавленной форме ref={formRef} и сразу после setValidated(true); того, как я это сделал handleReset(); , но затем проверка больше не работает.
Любые предложения по этому поводу приветствуются, а также любые комментарии к коду!

Вот пример того, что происходит при добавлении в тег формы и ref={formRef} :

   const formRef = useRef();
  const handleReset = () => {
    formRef.current.reset();
    setValidated(false);
  };
 

и в поисках:

       .then((response) => response.json())
      .then((response) => {
        if (response.status === "mail_sent") {
          setThankYouMessage(!thankYouMessage);
          handleReset();
        } else if (response.status === "mail_failed") {
          alert("Message failed to send.");
        }
      });
 

Проверка формы

Ответ №1:

Насколько я понимаю, вы хотите сначала получить ответ перед сбросом? e.preventDefault() это предотвращает сброс формы, но, удалив это, страница просто немедленно перезагружается, не дожидаясь ответа. Если это проблема, с которой вы столкнулись, то есть несколько решений:

  1. Используйте перезагрузку (просто перезагрузите текущий документ).
     .then((response) => {
            if (response.status === "mail_sent") {
              setThankYouMessage(!thankYouMessage);
            } else if (response.status === "mail_failed") {
              alert("Message failed to send.");
            }
            location.reload();
          });
 
  1. Используйте отправить (просто отправляет форму без отправки события отправки или проверки формы, но это нормально, потому что вы уже проверили ее ранее).
     const formRef = useRef(null);

    ...

    .then((response) => {
            if (response.status === "mail_sent") {
              setThankYouMessage(!thankYouMessage);
            } else if (response.status === "mail_failed") {
              alert("Message failed to send.");
            }
            formRef.current.submit();
          });

    ...

    <Form
      noValidate
      validated={validated}
      onSubmit={handleSubmit}
      ref={formRef}
    >    
 
  1. Используйте requestSubmit (то же самое, что и нажатие кнопки «Отправить»). EventListener здесь это необходимо, потому что, по сути, вы хотите отключить действие по умолчанию preventDefault , сначала позвонив, а затем снова включить действие по умолчанию после получения ответа. К сожалению, такой удобной enableDefault функции нет.

    Поток такой:

    1. addEventListener с preventDefault вызывается (теперь никакие нажатия кнопок не сбросят форму)
    2. Заполните форму и нажмите кнопку Отправить
    3. Извлечение и полученный ответ
    4. removeEventListener с preventDefault вызывается (теперь любые нажатия кнопок сбросят форму)
    5. вызовите requestSubmit , чтобы отправить форму, как если бы была нажата кнопка «Отправить», которая сбросит форму



     const formRef = useRef(null);

    ...

    // useCallback is needed here instead of a normal function because
    // formRef will be updated every time onChange occurs because react renders again
    // which will cause addEventListener/removeEventListener to not work as expected 
    const stopReset = useCallback((event) => {
        event.preventDefault();
        // stopPropagation will prevent form validation but if you really need it here
        // then you need to add another event listener for handleSubmit in useEffect
        // and you can remove onSubmit={handleSubmit} in Form
        // event.stopPropagation();
    }, []);

    useEffect(() => {
        formRef.current.addEventListener('submit', stopReset);
        // Uncomment this only if you need stopPropagation above
        // formRef.current.addEventListener('submit', handleSubmit);
    },[]); // Add dependencies in the array, leave it blank if you don't have any

    async function handleSubmit(e) {
        // remove preventDefault and stopPropagation here
    
        const formData = new FormData();
    
        Array.from(e.currentTarget.elements).forEach((field) => {
          if (!field.name) return;
          formData.append(field.name, field.value);
        });
    
        await fetch(
          "https://domain.tld/wp-json/contact-form-7/v1/contact-forms/1234/feedback",
          {
            body: formData,
            method: "POST",
          }
        )
          .then((response) => response.json())
          .then((response) => {
            if (response.status === "mail_sent") {
              setThankYouMessage(!thankYouMessage);
            } else if (response.status === "mail_failed") {
              alert("Message failed to send.");
            }
            formRef.current.removeEventListener('submit', stopReset);
            formRef.current.requestSubmit()
          });
    
        setValidated(true);
    }

    ...

    <Form
      noValidate
      validated={validated}
      onSubmit={handleSubmit}
      ref={formRef}
    >
 

Если вы хотите, чтобы ваше сообщение отображалось некоторое время перед сбросом, вы можете добавить таймер.

     .then(async (response) => {
            if (response.status === "mail_sent") {
              setThankYouMessage(!thankYouMessage);
            } else if (response.status === "mail_failed") {
              alert("Message failed to send.");
            }
            // sleep for 10 seconds
            await new Promise(r => setTimeout(r, 10000));
            // call whichever method to reset
          });
 

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

1. Я попробовал ваше первое решение 2 и не работает, потому что тогда проверка больше не работает. При этом он все равно отправляет форму без проверки. Когда я добавляю const formRef = useRef(); его, он все еще проверяется, но проверка не очищается при отправке формы.

2. @Марк, можешь ли ты попробовать первые 2 с таймером? Если вы хотите отменить проверку, вам setValidated(false); также нужно позвонить.

3. Конечно. Также ознакомьтесь с моим постом, просто добавили еще несколько объяснений и GIF, чтобы показать, что происходит при добавлении const formRef = useRef();

4. Когда я добавляю setValidated(false); в выборку if (response.status === "mail_sent") , она все равно не удаляет проверку, как показано в GIF в моем посте. Тем не менее, это очищает форму.

5. Можете ли вы попробовать сбросить настройки className ? formRef.current.className = "" или formRef.current.classList.remove("was-validated")