我有一个连接到Redux商店的组件,该组件接收道具并将其传递给子组件。
在子组件中,我通过render()
方法来详细说明该道具
let dataForFlatList = [].concat.apply([], [].concat.apply([], this.props.internalData.map( a => {
if(a.hasOwnProperty("components")){
a.components[a.components.length-1].lastItem = true
} else {
a.dayData.lastItem = true
}
return Object.values(a)
})));
为清楚起见,Redux商店中的此道具具有以下结构:
[
{
dailyData: {
date: .....
steps: .....
},
components: [ {...}, {...}, {...}, {...}, {...} ...]
},
{
dailyData: {
date: .....
steps: .....
},
components: [ {...}, {...}, {...}, {...}, {...} ...]
},
{
dailyData: {
date: .....
steps: .....
}
}
:::
]
因此,我想做的是向lastItem
数组中的最后一个对象添加属性components
;或者,如果components
不存在,则将lastItem
添加到对象dailyData
。
最后,仅需获得一系列concat()
即可获得一个没有嵌套对象的单个数组。
此代码有效,但是这里的一个奇怪的事实是,当我在map()
上调用this.props.internalData
函数时,商店内的道具internalData
也被编辑了。
您能帮助理解为什么发生吗?
谢谢
答案 0 :(得分:1)
Javascript通过引用传递对象。这意味着,如果克隆对象(所谓的“浅克隆”),则实际上会更改主对象引用,但嵌套属性保持不变。这就是当您 <xs:complexType name="NioLocationRequest">
<xs:complexContent>
<xs:extension base="tns:NioRequestBase">
<xs:sequence>
<xs:element name="forceCreation" type="xs:boolean"/>
<xs:element name="location" type="ns1:Location"/>
<xs:element name="replyTo" type="xs:string"/>
<xs:element minOccurs="0" name="roomZero" type="ns1:Room"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
对象数组或调用map
;
因此,当您像Object.assign({}, /.../)
一样更改某物时,实际上是在更改原始属性。地图将返回克隆的对象,但是此特定分配更改了原始属性的引用值。
为了解决它,您有多种方法:
a.dayData.lastItem = true
迭代中构造一个新对象); 此外,摆脱这些多个map
,可能不需要它们:)
解决方案:
1。。您可以尝试使用[].concat.apply
:https://lodash.com/docs/4.17.10#cloneDeep:
_.cloneDeep
但是要警告!对于大物体,它可能非常慢(它必须遍历所有结构)。
2。。您可以尝试像这样传递新值:
// Inside your map
const clonedA = _.cloneDeep(a);
if(clonedA.hasOwnProperty("components")){
clonedA.components[clonedA.components.length-1].lastItem = true
} else {
clonedA.dayData.lastItem = true
}
return clonedA;
在映射对象时,当我知道对象的状态时,我仍然更喜欢使用if(a.hasOwnProperty("components")){
// We use empty slice to clone the array
const clonedComponents = components.slice();
const lastArrayElement = clonedComponents[clonedComponents.length-1];
clonedComponents[clonedComponents.length - 1] = Object.assign({}, lastArrayElement, { lastItem: true });
return Object.assign({}, a, { components: clonedComponents});
} else {
// Note empty object as the first param - we also return completely new value
return Object.assign({}, a, { dayData: { lastItem: true } });
}
return Object.values(a);
或_.cloneDeep
(不要忘记使用_.merge
来调用Object.assign
第一个参数!),如果我知道这不会对性能产生重大影响。
就您而言,我建议遵循我的第二条建议-只需在数据结构的每个级别上创建一个新对象。我还建议将这些操作转移给助手,因为您会看到代码变得相当复杂且有些难看。