React动态表单中如何正确更新嵌套数组字段的值?

玉英🍀 阅读 36

我在用React做动态表单,允许用户添加多个联系人信息,每个联系人又有多个电话号码字段。现在遇到一个问题:当修改第二个联系人的第二个电话号码时,第一个联系人的最后一个号码也会跟着变。

我用useState保存表单数据结构是这样的:


const [formData, setFormData] = useState({
  contacts: [
    {
      name: '',
      phones: ['']
    }
  ]
});

处理电话输入的函数是这样的,感觉哪里错了:


const handlePhoneChange = (contactIndex, phoneIndex, value) => {
  const newContacts = [...formData.contacts];
  newContacts[contactIndex].phones[phoneIndex] = value;
  setFormData({...formData, contacts: newContacts});
};

试过用immer库还是不行,控制台显示state确实被修改了,但渲染时数据混乱。是不是因为嵌套对象没深拷贝?求指点具体应该怎么更新这种嵌套数组结构…

我来解答 赞 6 收藏
二维码
手机扫码查看
1 条解答
欧阳丽敏
这个问题确实是React开发中常见的坑,主要是因为直接修改了state的引用导致的。你的代码里虽然用了扩展运算符做了浅拷贝,但对深层嵌套的对象和数组来说,里面的引用还是原来的。

要解决这个问题,得确保每次更新都创建新的引用,而不是直接修改原有的数据结构。下面是一个正确处理嵌套数组字段更新的方法:

const handlePhoneChange = (contactIndex, phoneIndex, value) => {
setFormData(prevState => {
// 创建一个新的contacts数组
const updatedContacts = prevState.contacts.map((contact, index) => {
if (index === contactIndex) {
// 找到对应的联系人,创建一个新的phones数组
return {
...contact,
phones: contact.phones.map((phone, idx) =>
idx === phoneIndex ? value : phone
)
};
}
return contact;
});

// 返回新的formData对象
return { ...prevState, contacts: updatedContacts };
});
};


关键点在于:
1. 用 map 方法创建新的数组,而不是直接修改原数组
2. 对需要更新的那个联系人对象,也用扩展运算符创建了新对象
3. 通过 setFormData 的函数式更新,确保拿到的是最新的state

其实你之前的问题就出在 newContacts[contactIndex].phones[phoneIndex] = value 这一行,这里直接修改了原有数组的引用,导致React没法正确追踪变化。

还有个小建议,调试这种复杂状态的时候,可以在 useEffect 里监听 formData 的变化,打印出来看看是不是每次都生成了新的引用,能帮你更快发现问题。

如果觉得这样写太啰嗦,确实可以用immer库简化,但记得要用对方式。不过按照上面这个方法,基本就能解决问题了。
点赞
2026-02-16 12:01