I have a very simple React application that is exhibiting odd behavior:
import { useState } from 'react'
export function App(props) {
const [ready, setReady] = useState(false)
function handleSubmit(e) {
e.preventDefault()
alert("Submitted!")
}
return (
<form onSubmit={handleSubmit}>
{ ready ?
<button type="submit">Submit</button> :
<button type="button" onClick={() => setReady(true)}>Next</button> }
</form>
)
}
When I click the "Next" button, I expect the "Submit" button to appear but instead the form’s onSubmit
handler is triggered! What is causing this to occur, since the "Submit" button is never clicked?
5
Answers
I did some digging and found the source of the issue. (This page was helpful in explaining things.)
It turns out that rendering the same component in the same position in the UI tree causes React to reuse the underlying DOM element. So in the example above, the
<button>
element is reused when re-rendered afterready
is set totrue
.The correct way to avoid this is to set the
key
attribute on the two<button>
elements:With this change, the expected behavior is observed.
Incidentally, this is why the
key
attribute is required when rendering a list of elements (using.map()
for example) — to ensure that each item maintains correct state when items are added or removed.Update your button as Below:
Need to set "e.preventDefault()" for each button event.
You can also use
visibility
CSS to do the same, I am not sure why this happens, but this also solves your issue!play code
You can edit the code to bring out the Submit button from the form and conditionally display the next button based on the value of ready state:
You need to add preventDefault to the Next button as well.
Here is a working example.
https://codesandbox.io/p/sandbox/form-submission-forked-r3s3cl?file=%2Fsrc%2FApp.js%3A2%2C1-32%2C1