This is test code. When I click update button, it calls the updateItem
function and then handleSubmit
function, but when I click delete button, it calls only removeItem
function. Both buttons are type="submit"
button types.
import React, { useState } from "react";
function MyForm() {
const [items, setItems] = useState([
{ id: 1, name: "item1" },
{ id: 2, name: "item2" },
{ id: 3, name: "item3" },
]);
const removeItem = (id: number) => {
setItems(items.filter((item) => item.id !== id));
};
const updateItem = (id: number) => {
setItems(
items.map((item) => {
if (item.id === id) {
return { ...item, name: "test" };
} else {
return item;
}
})
);
};
const handleSubmit = (event: any) => {
event.preventDefault();
console.log("submit");
};
return (
<form onSubmit={handleSubmit}>
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name}
<button type="submit" onClick={() => removeItem(item.id)}>
Remove
</button>
<button type="submit" onClick={() => updateItem(item.id)}>
Update
</button>
</li>
))}
</ul>
</form>
);
}
export default MyForm;
I expect that delete button call onClick
event and then submit event like update button.
Hey, first let's understand what is happening here.
When you click Update, React runs your onClick
(which only changes state), then the button remains mounted, so the browser continues to fire the form’s native submit
event, which React catches in your handleSubmit
. But when you click Remove, your onClick
immediately unmounts that <li>
(and its <button>
), so the original submit action never makes it up to the <form>
—the button you clicked is gone before the browser has a chance to complete the submit step. The fix is to avoid relying on the native click→submit sequence for Remove; instead, make Remove a plain button and explicitly tell the form to submit after you remove the item. The modern, standards-compliant way is to call the form’s [requestSubmit()
][turn0search0] method, which behaves just like clicking a submit button (including running onSubmit
), but won’t be interrupted by your unmount.
The Fix: Use requestSubmit()
function MyForm() {
const [items, setItems] = useState([
{ id: 1, name: "item1" },
{ id: 2, name: "item2" },
{ id: 3, name: "item3" },
]);
const removeItem = (id) => {
setItems(items.filter(item => item.id !== id));
};
const handleSubmit = (event) => {
event.preventDefault();
console.log("submit");
};
return (
<form onSubmit={handleSubmit}>
<ul>
{items.map(item => (
<li key={item.id}>
{item.name}
{/* UPDATE can stay submit-type */}
<button
type="submit"
onClick={() => {
// ...update logic here
}}
>
Update
</button>
{/* REMOVE as plain button, then requestSubmit */}
<button
type="button"
onClick={e => {
// 1) remove it
removeItem(item.id);
// 2) then tell the form to submit
e.currentTarget.form.requestSubmit();
}}
>
Remove
</button>
</li>
))}
</ul>
</form>
);
}
type="button"
?
Prevents the browser’s built-in click→submit before you’ve unmounted the button.requestSubmit()
?
Unlike form.submit()
, [requestSubmit()
][turn0search2] exactly emulates a
user click
on a submit button—running validations and firing your React
onSubmit
handler.This is the minimal, robust change that ensures Remove always does its work then triggers your form’s submit logic.