本文详解 react 状态数组删除操作的常见错误——包括闭包捕获过期状态、`splice` 副作用隐患,以及 `value` 与 `defaultvalue` 混用导致的 ui/状态不一致问题,并提供符合 react 最佳实践的函数式更新方案。
在 React 中安全地从状态数组中删除指定索引的元素,关键在于始终基于最新状态进行不可变更新,并正确处理表单控件的受控性。原始代码的问题具有典型性:它使用了 splice()(直接修改原数组)、依赖闭包中捕获的 gridData.data(可能已过期),且在后续渲染中通过 gridData.data[1].description 访问被删项——这会导致读取越界或显示错误数据。
应完全避免 splice() 和临时变量拷贝(如 [...gridData.data] 后再 splice),而改用 filter() 配合函数式 setState:
const delData = (ndx) => {
setGridData((prevGridData) => ({
...prevGridData,
data: prevGridData.data.filter((_, index) => index !== ndx)
}));
};该写法确保:
你观察到将 改为 后删除逻辑“失效”,本质是受控组件(Controlled)与非受控组件(Uncontrolled)的根本区别:
✅ 正确实践:对动态列表中的输入框,必须使用 value + onChange 实现双向绑定,确保 UI 与 state 严格同步:
updateDescription(rndx, e.target.value)} />
export default function App() {
const [gridData, setGridData] = useState({
field1: "Placeholder",
data: []
});
const initialData = [
{ numstart: 1, numend: 1, description: "Wine - Taylors Reserve", rate: 83.3 },
{ numstart: 2, numend: 2, description: "Hot Choc Vending", rate: 3.07 },
{ numstart: 3, numend: 3, description: "Absolut Citron", rate: 75.65 },
{ numstart: 4, numend: 4, description: "Flour - Strong", rate: 33.16 }
];
useEffect(() => {
setGridData(prev => ({ ...prev, data: initialData }));
}, []);
const delData = (ndx) => {
setGridData(prev => ({
...prev,
data: prev.data.filter((_, index) => index !== ndx)
}));
};
return (
Current Description at Index 1: {gridData.data[1]?.description ?? 'N/A'}
Current Record Count: {gridData.data.length}
);
}? 提示:访问 gridData.data[1] 前务必使用可选链 ?. 或提供 fallback(如 'N/A'),防止删除后索引越界报错。
遵循以上原则
