Я пытаюсь условно переключаться между двумя кнопками HTML в ReactJS в зависимости от того, отображается форма или нет. По сути, если форма отображается, покажите кнопку отправки, а если она не отображается, покажите обычную кнопку для отображения формы.
Это код, который у меня есть. (Я использую компонент кнопки Antd, но я также пробовал использовать обычную кнопку HTML и столкнулся с той же проблемой.
<div>
{showForm ? (
<Button
loading = {isUploading}
htmlType = "submit"
form = "videoForm"
className = {Styles.button}
>
{isUploading ? 'Uploading' : 'Upload Video'}
</Button>
) : (
<Button
htmlType = "button"
onClick = {() => setShowForm(true)}
className = {Styles.button}
>
{successMsg ? 'Upload Another Video' : 'Show Form'}
</Button>
)}
</div>
Проблема, с которой я столкнулся, заключается в том, что когда форма не отображается и я нажимаю кнопку «Показать форму», форма отображается правильно, и кнопки переключаются, но запускается событие отправки формы, а это не то, что я ожидал или хотел.
Есть идеи, почему? И как я могу решить эту проблему? Я также попробовал сделать следующее, но получил те же результаты.
<div>
<Button
loading = {isUploading}
htmlType = {showForm ? 'submit' : 'button'}
form = "videoForm"
className = {Styles.button}
>
{showForm && (isUploading ? 'Uploading' : 'Upload Video')}
{!showForm && (successMsg ? 'Upload Another Video' : 'Show Form')}
</Button>
</div>
Любая помощь будет принята с благодарностью.
попробуй поставить setShowForm
в setTimeout
<button onClick = {() => setTimeout(() => setShowForm(true))}>...</button>
Кнопки внутри формы всегда действуют как кнопка отправки. Вы можете предотвратить это, добавив дополнительную функцию для события onClick и PreventDefault(), когда тип кнопки — «кнопка».
Это поведение не связано со значением type
по умолчанию для <button>
, поскольку OP уже устанавливает <button>
базового HTML-элемента type
на 'button'
через опору htmlType
.
Это поведение также можно воспроизвести без React, как показано ниже:
const form = document.getElementById('form'),
btnWo = document.getElementById('btn-wo'),
btnW = document.getElementById('btn-w');
form.onsubmit = function (event) {
console.info('form onsubmit');
event.preventDefault();
}
btnWo.onclick = function (event) {
console.info(`btn-wo onclick, type = ${this.type}`);
}
btnW.onclick = function (event) {
console.info(`btn-w onclick, type = ${this.type}`);
this.type = 'submit';
}
<form id = "form">
<button id = "btn-wo" type = "button">Button without Changing Type</button>
<button id = "btn-w" type = "button">Button with Changing Type</button>
</form>
При нажатии «Кнопки с изменяющимся типом» ее type
меняется на 'submit'
в обработчике событий. После того, как обработчик события возвращается, форма отправляется, потому что нажатый <button>
type
теперь 'submit'
.
То же самое происходит и в примере OP, поскольку React не перемонтирует компонент <Button>
(и базовый HTML-элемент <button>
), изменяется только свойство htmlType
(и свойство type
базового элемента).
Чтобы это исправить, либо:
preventDefault()
внутри прослушивателя событий. Это предотвратит действие по умолчанию — нажатие кнопки отправки <button>
, связанное с формой, которая отправляет форму.const { useState } = React;
const App = () => {
const [showForm, setShowForm] = useState(false);
const onSubmit = (event) => {
console.info("form onSubmit");
event.preventDefault();
setShowForm(false);
};
return (
<div>
<div>
{showForm ? (
<button type = "submit" form = "videoForm">
Upload Video
</button>
) : (
<button
type = "button"
onClick = {(event) => {
setShowForm(true);
event.preventDefault();
}}
>
Show Form
</button>
)}
{showForm && (
<form id = "videoForm" onSubmit = {onSubmit}>
<input />
</form>
)}
</div>
</div>
);
};
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
<div id = "root"></div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<button>
на type
после таймаута. Это работает, потому что 'submit'
<button>
все еще находится type
в момент возврата обработчика событий.const { useState } = React;
const App = () => {
const [showForm, setShowForm] = useState(false);
const onSubmit = (event) => {
console.info("form onSubmit");
event.preventDefault();
setShowForm(false);
};
return (
<div>
<div>
{showForm ? (
<button type = "submit" form = "videoForm">
Upload Video
</button>
) : (
<button type = "button" onClick = {() => setTimeout(() => setShowForm(true))}>
Show Form
</button>
)}
{showForm && (
<form id = "videoForm" onSubmit = {onSubmit}>
<input />
</form>
)}
</div>
</div>
);
};
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
<div id = "root"></div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
'button'
на type
; используйте по 1 элементу <button>
для каждого типа. В React для достижения этой цели вы можете использовать реквизит <button>
на одном из компонентов/элементов.const { useState } = React;
const App = () => {
const [showForm, setShowForm] = useState(false);
const onSubmit = (event) => {
console.info("form onSubmit");
event.preventDefault();
setShowForm(false);
};
return (
<div>
<div>
{showForm ? (
<button type = "submit" form = "videoForm">
Upload Video
</button>
) : (
<button type = "button" onClick = {() => setShowForm(true)} key = "s-btn">
Show Form
</button>
)}
{showForm && (
<form id = "videoForm" onSubmit = {onSubmit}>
<input />
</form>
)}
</div>
</div>
);
};
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
<div id = "root"></div>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
Помните, что по умолчанию
type
изbutton
элементов —submit
. Попробуйте добавитьtype = "button"
к обычной кнопке.