How to update multiple nested objects in Redux

时间:2016-06-18 20:20:09

标签: arrays object reactjs redux immutable.js

Given the following Array of objects how would one update all of the qty's in each of the nested "locationData" Arrays Objects? By all, I mean not just all in the Object, but all in all Objects. The base object is say an Item and the locationData is locations the items are in.

What I am doing is displaying all Items with the locations to the user and the user can then click different buttons to distribute the un-allocated Quantity to the locations, which will update all of the objects with the chosen distribution.

  1. Would I loop through the data in the React component and do a dispatch for each Item with a new locationData Array, replacing the old one?
  2. Would I loop through the Items in the Actions and then call the Reducer with an entirely new Array of items with the new locationData?

I can do it with or without ImmutableJs, but I am not sure the best way to do this.

[
{   
    "isSelected":false,
    "itemid":"2557",
    "name":"Accessories : Awesome Cable",
    "quantity":6000,"quantityByCase":600,
    "locationData":[
        {"id":"5","name":"QA Location","enabled":true,"percentage":"200","shipcarrier":"","shipmethod":"","qty":0},
        {"id":"7","name":"Single Bin Location","enabled":true,"percentage":"50","shipcarrier":"","shipmethod":"","qty":0},
        {"id":"1","name":"Warehouse - East Coast","enabled":true,"percentage":"","shipcarrier":"1","shipmethod":"92","qty":0}
    ],
    "unAllocatedQuantityByCase":600
},
{
    "isSelected":false,
    "itemid":"40",
    "name":"Accessories : Crusher Game Pad",
    "quantity":50,"quantityByCase":50,
    "locationData":[
        {"id":"5","name":"QA Location","enabled":true,"percentage":"200","shipcarrier":"","shipmethod":"","qty":0},
        {"id":"7","name":"Single Bin Location","enabled":true,"percentage":"50","shipcarrier":"","shipmethod":"","qty":0},
        {"id":"1","name":"Warehouse - East Coast","enabled":true,"percentage":"","shipcarrier":"1","shipmethod":"92","qty":0}
    ],
    "unAllocatedQuantityByCase":50}]

Currently, I am doing the the calculations in my reducer EVEN_DISTRIB, but this does not feel right. What I am doing is taking the entire state and mapping it to the items variable. items.isSelected is hard coded to true at the moment for testing. I then do an even distribution of the 'unAllocatedQuantityByCase' for each item and then lastly return all of the items and the new state for this reducer. There will also be weighted and like item distributions later, but wanted to get the even distribution right before proceeding further.

export default function (state = [], action) {
  switch (action.type) {
   case types.PO_RECEIVED:
     return state.concat(action.payload);

   case types.EVEN_DISTRIB: {
    let items = state.map(item => {
      item.isSelected = true;
      if (item.isSelected) {
        let quantity = item.unAllocatedQuantityByCase;
        let updateLocations = item.locationData.filter(location => location.enabled);
        let remainder = quantity % updateLocations.length;
        let divideqty = (quantity - remainder) / updateLocations.length;

        let loc = updateLocations.map(location => {
          var tempQty = divideqty;
          if (remainder >= 1) {
            tempQty++;
            remainder--;
          } else if (remainder > 0) {
            tempQty += remainder;
            remainder = 0;
          }
          location.qty = tempQty;
          return location
        });
        item.locationData = loc;
      }
      return item;
    });

    return items;
  }

  default:
    return state;
}}

Should these types of calculations be done in the reducer? or should I do them in the component and then call the action with this as the payload? or is there a better way to do this... Normalizing the data structure and then just updating all of the locations. I guess my question is where do these types of calculations take place in a React/Redux app?

2 个答案:

答案 0 :(得分:0)

  1. 操作:是仅返回操作对象的函数。行动中没有逻辑。
  2. 我是否会遍历React组件中的数据,并使用新的locationData数组为每个Item执行调度,替换旧的?: 这只会导致不必要的重新渲染,导致状态将发生变化每次发货时。
  3. 显示一些代码 让你的问题清楚,以便其他人可以从中学习。并且请显示一些代码,说明您正在尝试做什么或明确并在解释中指出。 期待着帮助你。

答案 1 :(得分:0)

首先,在Redux存储中组织嵌套或关系数据的一般建议方法是对其进行规范化,就像数据库中的表一样。这使您的州更平坦,更容易管理。有关该概念的更多信息,请参阅http://redux.js.org/docs/FAQ.html#organizing-state-nested-datahttps://medium.com/@adamrackis/querying-a-redux-store-37db8c7f3b0f

其次,虽然您需要决定拆分更新逻辑的准确程度,但通常应该在操作创建器或缩减器中完成工作,但组件中的不是http://redux.js.org/docs/FAQ.html#structure-business-logic提供了一些关于如何考虑拆分逻辑的建议。有些人会在他们的动作创建者中完成所有工作,并让他们的减速器简单地将动作内容合并到商店中,其他人将让动作创建者只是发送并让减速器完成所有工作。我个人在中间位置 - 我尝试将足够的信息放入减速器执行工作的动作中,并且我愿意让动作创建者需要准备计算,但更喜欢保持动作的内容相对最小的。

第三,您当前的减速器逻辑看起来过于复杂。至少,我建议将其分解为更容易思考的更小,更简单,更纯粹的辅助函数。另外,请记住,使用Redux时,您应该“不可变地”更新数据,即始终进行复制和修改副本,而不是修改原始版本。行location.qty = tempQty;似乎直接改变了一些原始数据,这通常会导致您的React组件无法正确更新。 (显然item.selected = true行也是如此。)