Try this code, set manually the initial value of the showSubmitButton
state to either true
or false
and you'll see that so far so good, the onSubmit
event is looking for an input of type submit to fire and all works fine.
you can also notice that the component rerenders before the onSubmit event handler runs.
import { useState } from "react";
const App = () => {
const [counter, setCounter] = useState(0);
const [showSubmitButton, setShowSubmitButton] = useState(true);
return (
<>
{console.log("component rerender and counter is: ", counter)}
<form
onSubmit={(e) => {
console.log(e);
e.preventDefault();
console.log("form submitted!");
}}
>
{showSubmitButton ? (
<button
type="submit"
onClick={(e) => {
console.log("submit button clicked");
setCounter((prev) => prev + 1);
// setShowSubmitButton((prev) => !prev);
}}
>
Submit
</button>
) : (
<button
type="button"
onClick={() => {
console.log("simple button clicked");
setCounter((prev) => prev + 1);
// setShowSubmitButton((prev) => !prev);
}}
>
Button
</button>
)}
</form>
</>
);
};
export default App
the drama begins when you uncomment setShowSubmitButton((prev) => !prev)
in the submit button.
now when you click it and toggle showSubmitButton
, the component rerenders it is like the onSubmit
event is triggered but cannot fire because the component rerenders and the input of type submit which is mandatory to do so cannot be found so nothing happens, till now, neither one of the two buttons is triggering onSubmit
.
now uncomment setShowSubmitButton((prev) => !prev)
in the simple button.
you'll see when you click that button the onSubmit
event is firing and if you check e.target
from inside onSubmit
you will find it equal to
<form>
<button type="submit">Submit</button>
</form>
so when you click the submit button, it seems like the onSubmit
event is stuck because the input of type submit cannot be found therefore when you click the simple button, the input of type submit is back to DOM, so the event handler can finally find it and run.
I know this is crazy, but it is the only explanation, there is no way that the simple button is triggering onSubmit
.
if you move state updates inside the event handler after e.preventDefault()
:
<>
{console.log("component rerender and counter is: ", counter)}
<form
onSubmit={(e) => {
console.log(e);
e.preventDefault();
console.log("form submitted!");
setCounter((prev) => prev + 1);
setShowSubmitButton((prev) => !prev);
}}
>
{showSubmitButton ? (
<button
type="submit"
onClick={(e) => {
console.log("submit button clicked");
}}
>
Submit
</button>
) : (
<button
type="button"
onClick={() => {
console.log("simple button clicked");
}}
>
Button
</button>
)}
</form>
</>
);
you will see it working as expected! because the component will rerender only when the code inside the onSubmit
event handler function finishes