我的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都被该数据覆盖,尽管在state和openApp中都使用了分散运算符。状态为untouchedApplications的数组不会在应用程序或方法中的任何位置使用,但也会得到更新。另外,分配给克隆数组的newProp属性在具有数据的原始数组中不存在,但是在将其添加到克隆数组后的状态下确实会应用于两个数组。
我还尝试使用Array.from
和state.applications.slice()
创建克隆。我在这里感到有点迷茫,因为我确定这是克隆数组的正确方法。
对不起,我的代码缩进很乱。我不知道如何正确设置SO格式。第一行位于其他行之前,或者所有行均始于8个制表符。对此也有任何提示。
答案 0 :(得分:1)
您应该使用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)
答案 1 :(得分:1)
您要使用的数组是对象数组。对象是引用类型,这意味着,实际上,您的数组包含对对象的引用。
当您将数组扩展到新数组中时,您不是在克隆对象,而只是在克隆它们的引用,因此,当您编写clone[appIndex]
时,您是在引用两个数组中包含的同一对象。
要解决此问题,可以使用map
方法克隆要更改的对象:
const newArray = ApplicationsData.map(
(item, index) =>
index == appIndex ?
({
...item,
isActive: true,
newProp: true,
isMinimized: false
}) :
item
);
这将返回所有项目的原始对象引用,但您要更改的特定项目除外。在这种情况下,它将创建一个全新的对象并返回该引用,因此原始对象将保持不变。