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>
)
}
https://playcode.io/1741452
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?
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 after ready is set to true.
The correct way to avoid this is to set the key attribute on the two <button> elements:
// ...
{ ready ?
<button key="submit" type="submit">Submit</button> :
<button key="next" type="button" onClick={() => setReady(true)}>Next</button> }
// ...
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With