React“神奇地”更新两种状态而不是一种

分享于2022年07月17日 ecmascript-6 javascript reactjs state 问答
【问题标题】:React“神奇地”更新两种状态而不是一种(React "magically" updates two states instead of one)
【发布时间】:2022-07-11 21:21:59
【问题描述】:

我有两个这样定义的状态:

  const [productProperties, setProductProperties] = useState<
    PropertyGroup[] | null
  >(null);
  const [originalProductProperties, setOriginalProductProperties] = useState<
    PropertyGroup[] | null
  >(null);

第一个应该通过用户输入更新,第二个稍后用于比较,以便只有更改值的 PropertyGroup 将通过API提交以进行更新。

我之前已经这样做了一千次,但是由于某种原因,当我更改 PropertyGroup name 值并像这样更新“productProperties”的状态时:

  (e, itemId) => {
    const update = [...productProperties];
    const i = update.findIndex((group) => group.id === itemId);
    if (i !== -1) {
      update[i].name = {
        ...update[i].name,
        [selectedLocale]: e.currentTarget.value,
      };
      setProductProperties([...update]);
    }
  }

originalProductProperties 的状态也会更新。为什么? setOriginalProductProperties 从未在这里被调用,我也没有直接改变任何状态,我使用扩展运算符来确保创建新的引用。我迷路了。

  • 你能提供一个最小的、可重现的例子吗?旁注:您可以使用 map() 方法简化状态更新逻辑。

【解决方案1】:

前言:听起来这两个数组共享相同的对象。只要您正确处理更新就可以了。

虽然您正在复制 数组 ,但您正在直接修改数组中的对象。这违反了国家的主要规则: Do Not Modify State Directly

相反,也制作对象的副本:

(e, itemId) => {
    const update = [...productProperties];
    const i = update.findIndex((group) => group.id === itemId);
    if (i !== -1) {
        update[i] = { // *** Note making a new object
            ...update[i],
            [selectedLocale]: e.currentTarget.value,,
        };;
        setProductProperties([...update]); // (No need to *re*copy the array here, you've already done it at the top of the function)
    }
}