You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS中删除状态数组元素的异常行为及原因排查

问题解决:React删除数组元素后渲染异常(与input的value/defaultValue相关)

问题重现

你最初尝试删除React状态数组中的元素时,发现newList已经正确移除了目标记录,但状态更新后显示被删除的却是最后一条记录;后续改用filter方法删除后代码正常,但将input的value改为defaultValue时,再次出现删除最后一个元素的异常。

核心原因

这是React列表渲染的DOM复用机制结合非受控组件特性导致的:

  1. 缺少唯一key:当用map渲染列表时,若未给每个元素设置唯一且稳定的key,React会默认使用数组索引作为key。删除中间元素后,数组索引重新排列,React会复用原有DOM节点而非重新创建,这会导致视图和状态不同步。
  2. defaultValue的特性:defaultValue是给非受控input设置初始值的属性,组件挂载后该值不会随状态更新而变化。当React复用DOM节点时,旧的defaultValue不会被替换,视觉上就出现了“删错元素”的假象——实际状态已正确更新,但DOM显示的还是旧的初始值。
  3. value正常的原因:使用value时input变为受控组件,状态更新会强制同步input的值,即使DOM被复用,内容也会被正确更新,因此不会出现显示偏差。

解决方案

给列表渲染的每个元素添加唯一且稳定的key(不要用数组索引,要用数据本身的唯一标识,比如你的numstart字段),同时优化删除逻辑,用数据唯一标识代替索引:

export default function App() {
  const [gridData, setGridData] = useState([
    {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 },
    { numstart: 5, numend: 5, description: "Cauliflower", rate: 33.37 },
    { numstart: 6, numend: 6, description: "Appetizer - Seafood Assortment",rate: 10.7},
    { numstart: 7, numend: 7, description: "Lemonade - Island Tea, 591 Ml", rate: 84.91}
  ]);
  
  // 用numstart唯一标识删除,避免索引变化导致的错误
  const delData = (targetId) => {
    setGridData(prev => prev.filter(item => item.numstart !== targetId));
  };

  const buildRows = () => {
    return gridData.map((r) => {
      return (
        // 绑定唯一key,让React能正确识别每个列表项
        <div key={r.numstart} style={{ display: "flex" }}>
          <button onClick={() => delData(r.numstart)}>Delete</button>
          <div>
            <input 
              id={`desc-${r.numstart}`} 
              defaultValue={r.description} 
            />
          </div>
        </div>
      );
    });
  };
  
  return <div className="App">{buildRows()}</div>;
}

额外提示

  • 永远不要用数组索引作为列表元素的key,尤其是当列表有增删操作时,索引会变化,导致React的DOM复用逻辑出错。
  • 受控组件(用value)适合需要实时同步状态的场景,非受控组件(用defaultValue)适合不需要实时同步的场景,但都需要配合唯一key保证渲染正确。

内容的提问来源于stack exchange,提问作者Elcid_91

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 18:43:21