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

React删除列表对象后UI未正确重渲染Input组件如何解决

问题原因

你遇到的删除后UI不更新问题,是两个典型的React列表渲染错误叠加导致的,和初始空对象的设置没有直接关系:

  • 用数组索引作为列表key:React依赖key值判断组件是否需要更新、复用还是销毁。当你删除列表中间项时,后续项的索引会顺位前移,React会错误判定组件没有变化,直接复用之前的Input组件实例,连组件内部的value、submitted本地状态都不会重置,最终出现数据已更新但UI显示错位、看起来没删除的问题。
  • 列表项结构不统一+过滤逻辑漏洞:初始list值为[{}],这个空对象没有id字段,执行filter(item => item.id !== id)时,空对象的id是undefined,永远不等于传入的数字id,导致这个初始项永远不会被过滤掉,列表长度和实际渲染的组件数不匹配。
修复方案

按照以下三点调整即可,同时满足「列表至少保留1个输入项」的业务要求:

  1. 给每个列表项分配全局唯一、从创建到删除保持不变的id作为key,绝对不要用数组索引当key
  2. 统一所有列表项的数据结构,初始项也带上合法id,不要留没有id的空对象
  3. 调整提交、删除逻辑:提交时先更新当前项的输入值,再追加新的空输入项;删除时判断列表长度,长度为1时阻止删除,保证至少留1项。

修复后代码

父组件 App.jsx

import "./styles.css";
import { useState, useEffect } from "react";
import Input from "./Input";

// 生成唯一id的工具函数,也可以替换为现代浏览器原生支持的 crypto.randomUUID()
let idCounter = 0;
const getUniqueId = () => idCounter++;

export default function App() {
  // 初始项直接带上唯一id,结构和后续新增项统一
  const [list, setList] = useState([{ id: getUniqueId() }]);
  
  useEffect(() => {
    console.log("list", list);
  }, [list]);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      {list.map((item) => (
        // 用项自身的稳定id作为key,不要用数组索引i
        <div key={item.id}>
          <Input id={item.id} setList={setList} />
        </div>
      ))}
    </div>
  );
}

子组件 Input.jsx

import { useState } from "react";
// 实际使用时把getUniqueId抽到公共工具文件引入即可
let idCounter = 0;
const getUniqueId = () => idCounter++;

const Input = ({ setList, id }) => {
  const [value, setValue] = useState("");
  const [submitted, setSubmitted] = useState(false);

  const handleChange = (event) => {
    const result = event.target.value.replace(/\D/g, "");
    setValue(result);
  };

  const handleSubmit = () => {
    setList((list) => [
      // 先更新当前提交项的total值
      ...list.map(item => item.id === id ? {...item, total: value} : item),
      // 追加新的空输入项
      { id: getUniqueId() }
    ]);
    setSubmitted(true);
  };

  const handleDelete = () => {
    setList((list) => {
      // 列表只剩1项时阻止删除,满足至少1项的要求
      if (list.length <= 1) return list;
      return list.filter((item) => item.id !== id);
    });
  };

  return (
    <div>
      <input
        value={new Intl.NumberFormat("ko-KR", {
          style: "currency",
          currency: "KRW"
        }).format(Number(value))}
        onChange={handleChange}
        type="text"
      />
      {submitted ? (
        <button disabled={value.length === 0} onClick={handleDelete}>
          Delete
        </button>
      ) : (
        <button disabled={value.length === 0} onClick={handleSubmit}>
          Submit!
        </button>
      )}
    </div>
  );
};

export default Input;

修复后React可以通过稳定的key准确识别每个Input组件的增删,删除对应项时会直接销毁对应的组件实例,不会出现状态复用错位的问题,UI会和list状态完全同步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 13:51:29