在react / redux中,在商店prop上调用map()可在商店本身中编辑prop

时间:2018-10-12 15:12:03

标签: javascript reactjs

我有一个连接到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也被编辑了。

您能帮助理解为什么发生吗?

谢谢

1 个答案:

答案 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({}, /.../)一样更改某物时,实际上是在更改原始属性。地图将返回克隆的对象,但是此特定分配更改了原始属性的引用值。

为了解决它,您有多种方法:

  1. 克隆整个对象和每个属性(深层克隆)
  2. 不要更改属性,而只是传递一个新值(在每次a.dayData.lastItem = true迭代中构造一个新对象);

此外,摆脱这些多个map,可能不需要它们:)

解决方案:

1。。您可以尝试使用[].concat.applyhttps://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第一个参数!),如果我知道这不会对性能产生重大影响。

就您而言,我建议遵循我的第二条建议-只需在数据结构的每个级别上创建一个新对象。我还建议将这些操作转移给助手,因为您会看到代码变得相当复杂且有些难看。