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

React useEffect依赖data重渲染时Antd表单Input内容清空问题

界面截图

问题表现

当前UI存在重渲染清空输入框的问题:每次data状态变化触发组件重渲染时,输入框内已经填好的内容就会被清空,相关触发逻辑如下:

useEffect(() => {
  display();
}, [data]);

data不能从依赖项里移除——新增、删除区间操作后必须触发重渲染,才能展示最新的列表结构。现在的现象是初始加载时输入框能正常显示预设值,只要删除任意一个区间(比如3-4这个区间),所有输入框的内容都会被清空。

问题根因

三个写法问题共同导致了这个异常:

  • 列表渲染直接拿数组下标index当节点key:删除中间的区间项后,后面所有项的下标都会往前移,React做虚拟DOM对比时会认错节点,加上Antd Form是靠Form.Item的name属性匹配字段值,下标变了之后name跟着变,原有值匹配不上自然就显示为空。
  • 删除方法直接修改原始state:deleteNewRange里直接对data.Red.List调用splice,违反React状态不可变的要求,会导致状态更新链路异常,重渲染时拿不到正确的旧值。
  • 每次data变化就调用display()全量重置表单:相当于每次列表变更都把表单值重新覆盖一遍,删除项之后字段名和表单项的对应关系已经错乱,重置时匹配不到值就直接显示空。
修复方法
  1. 给每个区间项分配一个固定不变的唯一标识,渲染时用这个标识当key,同时Form.Item的name也绑定这个标识,不要跟着数组下标变化。唯一标识可以用第三方库生成,也可以自己维护一个自增数字实现,只要每个项的id不重复、不随列表位置变动即可。
  2. 修正删除逻辑,全程不要直接修改原state对象,通过不可变更新的方式生成新的状态对象再调用setData。
  3. 不要在data变化时全量重置表单,初始化表单值的逻辑只在组件首次加载时执行一次即可,新增项时单独给新项设置初始值,不要全量覆盖已有字段的输入内容。

修复后核心代码参考

// 可自行替换为更严谨的唯一id生成逻辑,比如引入uuid库、维护自增数字
const generateId = () => Math.random().toString(36).slice(2);

const App = () => {
  // 初始化时给每个区间项绑定固定id
  const [data, setData] = useState({
    Red: {
      Name: "R",
      List: [
        { id: generateId(), range: ["4", "6"] },
        { id: generateId(), range: ["3", "4"] },
        { id: generateId(), range: ["1", "2"] },
        { id: generateId(), range: ["7", "10"] }
      ]
    }
  });
  const [form] = Form.useForm();

  const deleteNewRange = (targetId) => {
    // 用filter返回新数组,不修改原state
    const newList = data.Red.List.filter(item => item.id !== targetId);
    setData({
      ...data,
      Red: {
        ...data.Red,
        List: newList
      }
    });
  };

  // 仅首次加载时初始化表单值
  useEffect(() => {
    const initValues = {};
    data.Red.List.forEach(item => {
      initValues[`startRange_${item.id}`] = item.range[0];
      initValues[`endRange_${item.id}`] = item.range[1];
    });
    form.setFieldsValue(initValues);
  }, []);

  return (
    <>
      <Form form={form}>
        {data.Red.List.map((item) => (
          // 用固定id作为key,Form.Item的name也绑定id,不会因为删除其他项变化
          <div key={item.id}>
            <Form.Item name={`startRange_${item.id}`}>
              <InputNumber />
            </Form.Item>
            <p>To</p>
            <Form.Item name={`endRange_${item.id}`}>
              <InputNumber/>
            </Form.Item>
            <div>Add</div>
            <div onClick={() => deleteNewRange(item.id)}>
              Delete
            </div>
          </div>
        ))}
      </Form>
      <Button type="primary" htmlType="submit">
        Save
      </Button>
    </>
  );
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:06:20