影响反应状态的克隆数组
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.from
和 state.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 引用,因此原始对象保持不变。
我在 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.from
和 state.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 引用,因此原始对象保持不变。