影响反应状态的克隆数组

Cloned arrays affecting react state

我在 React 应用程序中克隆数组时遇到问题。

我将一个包含数据的数组导入到我的名为 ApplicationsData 的应用程序中。这是一个对象数组。

import ApplicationsData from '../Store/Applications';

应用程序组件具有以下状态:

constructor(props) {
    super(props);    
    this.state = { 
        isOn: true,
        untouchedApplications: [...ApplicationsData],
        applications: [...ApplicationsData],
        activeWindows: [...defaultActive],
        background: "#3a6ea5"
    };
}

我使用“...”扩展运算符克隆了包含数据的数组。

在我的上下文中,我有一个方法 - openApp - 它会更改 state.applications 中元素中的 属性。

openApp: (appID) => {
                let appIndex = this.state.applications.findIndex( el => el.id == appID);
                let clone = [...ApplicationsData];
                
                clone[appIndex].isActive = true;
                clone[appIndex].newProp = true;
                clone[appIndex].isMinimized = false;
                this.setState({applications: clone})
            },

每当我到达 clone[appIndex].prop = value 时,state.applications 和 untouchedApplications 都会被该数据覆盖,尽管在状态和 openApp 中都使用了扩展运算符。 state 中的 untouchedApplications 数组未在应用程序或方法中的任何地方使用,但也会更新。此外,分配给克隆数组的 newProp 属性 不存在于带有数据的原始数组中,但在将其添加到克隆数组后确实应用于状态中的两个数组。

我也尝试过使用 Array.fromstate.applications.slice() 来创建克隆。我在这里感觉有点迷茫,因为我确定这是克隆阵列的正确方法。

对于乱七八糟的代码缩进,我深表歉意。我不知道如何正确设置 SO 格式。要么第一行在其他行之前,要么所有行都从 8 个制表符开始。对此的任何提示也将不胜感激。

你应该使用map函数

(appID) => {
   let clone = this.state.applications.map(item => {
        if (item.id == appId) {
            return {
                ...item,
                isActive: true,
                newProp: true,
                isMinimized: false
            }
        }
        return item;
    })    
    this.setState({applications: clone})
},

发生这种情况是因为当您使用 ... 运算符时,它会创建数组的浅拷贝而不是深拷贝。

let val = [{key: "value"}, {key: "value"}, {key: "value"}]
let copy = [...val];


let isEqualShallow = val[0] == copy[0]

console.log(isEqualShallow)

所以您可以看到副本中的第一个对象与另一个对象是如何相等的。但是,如果您也对内部对象使用扩展运算符,那么您将获得深层副本。

    let val = [{key: "value"}, {key: "value"}, {key: "value"}]
    let copy = val.map(item => {
      return {...item}
    })


    let isEqualDeep = val[0] == copy[0]

    console.log(isEqualDeep)

您正在使用的数组是对象数组。对象是引用类型,这意味着实际上,您的数组包含对对象的 引用

当您将数组展开到一个新数组中时,您并没有克隆对象,只是克隆它们的引用,因此当您写 clone[appIndex] 时,您 指的是同一个对象包含在两个数组中.

要解决这个问题,您可以使用 map 方法克隆您要更改的对象:

const newArray = ApplicationsData.map(
  (item, index) =>
    index == appIndex ?
      ({
         ...item,
         isActive: true,
         newProp: true,
         isMinimized: false
       }) : 
    item
);

这将 return 所有项目的原始对象引用,除了您要更改的特定项目。在这种情况下,它会创建一个全新的对象和 return 引用,因此原始对象保持不变。