[英]In react/redux, calling map() on a store prop edits the prop in the store itself
I have a component connected to the Redux store that receives a prop and passes it to a child component. 我有一个连接到Redux存储的组件,该组件接收一个prop并将其传递给子组件。
In the child component I elaborate this prop in the render()
method, in this way 在子组件中,我以这种方式在
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)
})));
For clarity, this prop in the Redux store has this structure: 为了清楚起见,Redux商店中的该道具具有以下结构:
[
{
dailyData: {
date: .....
steps: .....
},
components: [ {...}, {...}, {...}, {...}, {...} ...]
},
{
dailyData: {
date: .....
steps: .....
},
components: [ {...}, {...}, {...}, {...}, {...} ...]
},
{
dailyData: {
date: .....
steps: .....
}
}
:::
]
so, what I want to do is adding a property lastItem
to the last object in the components
array; 因此,我想做的是将一个属性
lastItem
添加到components
数组中的最后一个对象; or, if components
does not exist, adding lastItem
to the object dailyData
. 或者,如果不存在
components
, lastItem
添加到对象dailyData
。 Finally, that series of concat()
are just necessary to obtain a single array of no nested objects. 最后,只有一系列
concat()
才能获得没有嵌套对象的单个数组。
This code works, but the strange fact here is that when i call the map()
function on this.props.internalData
the prop internalData
inside the store is edited, too. 该代码有效,但是这里的一个奇怪的事实是,当我在
this.props.internalData
上调用map()
函数时,商店internalData
的prop internalData
也被编辑了。
Can you help to understand why it happens? 您能帮助您理解为什么会发生吗?
Thanks 谢谢
Javascript passes objects by reference. Javascript通过引用传递对象。 This means that if you clone the object (so called "shallow clone") you actually change the main object reference, but nested properties stay the same.
这意味着,如果克隆对象(所谓的“浅克隆”),则实际上会更改主对象引用,但嵌套属性保持不变。 That's exactly what happens when you
map
the array of objects or call Object.assign({}, /.../)
; 当您
map
对象数组或调用Object.assign({}, /.../)
时,就会发生这种情况。
Hence, when you change sth like a.dayData.lastItem = true
you actually mutate original property. 因此,当您像
a.dayData.lastItem = true
那样更改a.dayData.lastItem = true
,实际上是在更改原始属性。 Map will return cloned object, but this specific assignment changes the value of reference of the original property. Map将返回克隆的对象,但是此特定分配更改了原始属性的引用值。
In order to solve it, you have multiple approaches: 为了解决它,您有多种方法:
map
iteration); map
迭代中构造一个新对象); Also, get rid of these multiple [].concat.apply
, they're probably unneeded :) 另外,摆脱这些多个
[].concat.apply
,可能不需要它们:)
Solutions: 解决方案:
1. You can try using _.cloneDeep
: https://lodash.com/docs/4.17.10#cloneDeep : 1.您可以尝试使用
_.cloneDeep
: https : _.cloneDeep
:
// 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;
Be warned, though! 但是要警告! It might be very slow for big objects (it has to traverse all the structures).
对于大型物体,它可能非常慢(它必须遍历所有结构)。
2. You can try passing new value like that: 2.您可以尝试像这样传递新值:
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);
When mapping objects, I still prefer to use _.cloneDeep
or _.merge
when I know the state of the object (don't forget to call Object.assign
with {}
as the first argument!) if I know it won't have a significant impact for the performance. 映射对象时,如果我知道对象的状态,我仍然更喜欢使用
_.cloneDeep
或_.merge
(不要忘记使用{}
作为第一个参数调用Object.assign
!)。对性能有重大影响。
In your case, I'd suggest following my second suggestion - just create new object on every level of your data structure. 对于您的情况,我建议遵循我的第二条建议-只需在数据结构的每个级别上创建新对象。 I'd also recommend moving these operations to helpers, as you can see the code gets quite complicated and somewhat ugly.
我还建议将这些操作转移给助手,因为您会看到代码变得相当复杂且有些丑陋。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.