Когда мы используем тройной код для замены кнопки с type = "button"
на кнопку с type = "submit"
в форме в React, замененная кнопка приводит к отправке формы.
import {useState} from "react";
function App() {
const [isClicked, setIsClicked] = useState(false);
const handleClick = () => {
setIsClicked(true)
};
return (
<form action='/submitted'>
<div>
<label htmlFor = "firstName">First Name</label>
<input id = "firstName" name = "firstName" placeholder = "John"/>
</div>
<div>
<label htmlFor = "lastName">Last Name</label>{' '}
<input id = "lastName" name = "lastName" placeholder = "Doe"/>
</div>
{isClicked
? <button type = "submit">Submit</button>
: <button type = "button" onClick = {handleClick}>Click Me</button>}
</form>
)
}
export default App
Но если мы разделим тернарный код на два условных выражения, форма не будет отправлена.
import {useState} from "react";
function App() {
const [isClicked, setIsClicked] = useState(false);
const handleClick = () => {
setIsClicked(true)
};
return (
<form action='/submitted'>
<div>
<label htmlFor = "firstName">First Name</label>
<input id = "firstName" name = "firstName" placeholder = "John"/>
</div>
<div>
<label htmlFor = "lastName">Last Name</label>
<input id = "lastName" name = "lastName" placeholder = "Doe"/>
</div>
{isClicked ? <button type = "submit">Submit</button> : null}
{!isClicked ? <button type = "button" onClick = {handleClick}>Click Me</button> : null}
</form>
)
}
export default App
Кроме того, если замененный компонент не относится к тому же типу компонента, он не будет отправлен.
import {useState} from "react";
const SubmitButton = () => <button type = "submit">Submit</button>;
function App() {
const [isClicked, setIsClicked] = useState(false);
const handleClick = () => {
setIsClicked(true)
};
return (
<form action='/submitted'>
<div>
<label htmlFor = "firstName">First Name</label>
<input id = "firstName" name = "firstName" placeholder = "John"/>
</div>
<div>
<label htmlFor = "lastName">Last Name</label>
<input id = "lastName" name = "lastName" placeholder = "Doe"/>
</div>
{isClicked
? <SubmitButton/>
: <button type = "button" onClick = {handleClick}>Click Me</button>}
</form>
)
}
export default App
React пытается сделать что-то умное, но может ли кто-нибудь объяснить, почему это происходит?
Я понимаю, что новый элемент заменяется при запуске обработчика onClick. Однако я не понимаю, почему новый элемент считается нажатым, хотя это явно не так.
@TinouHD Тип элементов кнопок по умолчанию — type = "submit"
; Но добавлю для ясности.
мб ты прав, спасибо, что заметил это для меня
Вы можете решить эту проблему, используя свойство ключа React. React использует это свойство, чтобы отслеживать элементы на одном уровне в дереве компонентов.
import {useState} from "react";
function App() {
const [isClicked, setIsClicked] = useState(false);
const handleClick = () => {
setIsClicked(true)
};
return (
<form action='/submitted'>
<div>
<label htmlFor = "firstName">First Name</label>
<input id = "firstName" name = "firstName" placeholder = "John"/>
</div>
<div>
<label htmlFor = "lastName">Last Name</label>{' '}
<input id = "lastName" name = "lastName" placeholder = "Doe"/>
</div>
{isClicked
? <button key = "submit" type = "submit">Submit</button>
: <button key = "button" type = "button" onClick = {handleClick}>Click Me</button>}
</form>
)
}
export default App
Ах, интересно! Я думал это только для петель.
Вы уже нашли решения, но я думаю, что вам нужно объяснение.
Причина: «Распространение событий и привязка».
Объяснение:
Представьте, что у вас есть форма с кнопкой отправки, нажатие которой должно отправить данные формы на сервер. Однако в вашем случае кнопка отправки появляется при нажатии другой кнопки. В вашем первом фрагменте кода обе кнопки уже отрисованы с помощью реакции. Разница лишь в том, что один из них отображается вам на основе isClicked. Форма привязана к кнопке отправки под капотом.
Здесь происходит следующее: когда вы нажимаете на первую кнопку, Событие щелчка распространяется на форму.
Достигнув формы, React находит кнопку отправки. которое вызвало событие щелчка (которое уже обнаруживается, когда вы нажал на другую кнопку) и находит его.
Следовательно, это вызывает отправку формы.
Почему разделение условий сработало?
Когда вы разделяете условия, отправка не отображается и не присутствует при первоначальном рендеринге.
Поскольку на этот раз кнопка отправки не привязана к форме (когда вы использовали тройную кнопку, кнопка была там, визуализирована, привязана, но скрыта из-за условия), событие не распространяется на форму
Надеюсь, вам понравилось объяснение, это был интересный сценарий и вопрос, и чтобы понять это, потребовалось некоторое тестирование.
Похоже, это связано с процессом согласования React и алгоритмом сравнения: https://legacy.reactjs.org/docs/reconciliation.html
Элементы DOM одного типа При сравнении двух элементов React DOM одного и того же типа React просматривает атрибуты обоих, сохраняет один и тот же базовый узел DOM и обновляет только измененные атрибуты.
Когда мы используем тройной элемент, элементы считаются одним и тем же узлом, поэтому, когда элементы на обеих сторонах тройного элемента совпадают, React обновит предыдущий узел на месте.
В документах React указано, что рекомендуемым средством решения этой проблемы является размещение ключей на элементах, как указано в ответе @TinouHD.
Когда у детей есть ключи, React использует их для сопоставления детей в исходном дереве с детьми в последующем дереве.
Вот почему это будет работать:
{isClicked
? <button key = "submit" type = "submit">Submit</button>
: <button key = "button" type = "button" onClick = {handleClick}>Click Me</button>}
Запуск отправки при нажатии не является проблемой, специфичной для React, см. этот чистый HTML и JS:
<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<meta name = "viewport" content = "width=device-width">
<title>Swap button pure JS demo</title>
</head>
<body>
<form onsubmit = "alert('submitted with swapped attribute')">
<button type = "button" id = "button">Click me</button>
</form>
<script>
document.getElementById("button").addEventListener("click", function (e) {
e.target.setAttribute("type", "submit");
})
</script>
</body>
</html>
В последнем примере кода вы определяете
SubmitButton
как простую кнопку HTML безtype = "submit"
. Я думаю, именно поэтому в этом примере не происходит отправка.