#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()
это предотвращает сброс формы, но, удалив это, страница просто немедленно перезагружается, не дожидаясь ответа. Если это проблема, с которой вы столкнулись, то есть несколько решений:
- Используйте перезагрузку (просто перезагрузите текущий документ).
.then((response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
location.reload();
});
- Используйте отправить (просто отправляет форму без отправки события отправки или проверки формы, но это нормально, потому что вы уже проверили ее ранее).
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}
>
- Используйте requestSubmit (то же самое, что и нажатие кнопки «Отправить»).
EventListener
здесь это необходимо, потому что, по сути, вы хотите отключить действие по умолчаниюpreventDefault
, сначала позвонив, а затем снова включить действие по умолчанию после получения ответа. К сожалению, такой удобнойenableDefault
функции нет.Поток такой:
addEventListener
сpreventDefault
вызывается (теперь никакие нажатия кнопок не сбросят форму)- Заполните форму и нажмите кнопку Отправить
- Извлечение и полученный ответ
removeEventListener
сpreventDefault
вызывается (теперь любые нажатия кнопок сбросят форму)- вызовите
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")