更新react redux中的深层嵌套状态(规范化)

Update deep nested state (normalized) in react redux

本文关键字:状态 嵌套 规范化 react redux 更新      更新时间:2023-09-26

我试图在React/Redux中创建一个航班搜索应用程序,在主屏幕中显示我所有的航班结果,并在侧边栏中显示不同类型的过滤器作为复选框。(作为一个例子,参见这个例子

过滤器按类型分组,例如出发站、到达站、出发时间等。所有的过滤器元素都在一个规范化的嵌套状态下创建,其中每个元素都具有以下属性:

"type": "airlines",           // this is the group type 
"checked": true,              // will be switched true or false
"label": "Brittish Airways"   // this is the display label

当我单击React视图中的一个复选框时,将触发以下操作:

export function filterFlightOffers(item, index) {
    return {
        type: 'FILTER_FLIGHT_OFFERS',
        grouptype,
        id
    }
}

我希望我的redux减速器更新状态(开关检查值)并返回新状态(例如不可变)。查看在线示例,我反应解决方案,如使用扩展操作符复制新状态,例如. ...用被选中的项来状态和更新特定的元素,例如{[action]。Id]: checked, !checked}。

但是我就是不能让它工作,我想由于我有一个深嵌套状态…因此,我删除了操作和reducer的复杂性,并制作了一个简单的jsfiddle,它应该只是console.log一个新的不可变的'changed'状态。

有人能帮我吗?

http://jsfiddle.net/gzco1yp7/4/

谢谢!

如果你的状态是这样的:

{    
  result: [1,2,3,4],
  entities: {
    searchitems: {
      1: {
        "type": "matchAirlines",
        "checked": false,
        "label": "Match airlines"
      }, 
      2: {
        "type": "airlines",
        "checked": true,
        "label": "Air France"
      },
      3: {
        "type": "airlines",
        "checked": true,
        "label": "Brittish Airways"
      }
    }, 
    counts:
      1: { "count": 2001 }, 
      2: { "count": 579 },
      3: { "count": 554 } 
    } 
  }
}

…您的减速器可能看起来像这样:

function reducer(state, action) {
  switch (action.type) {
    case 'FILTER_FLIGHT_OFFERS':
      return {
        ...state,
        entities: {
          ...state.entities,
          searchItems: Object.keys(state.entities.searchItems).reduce((newItems, id) => {
            const oldItem = state.entities.searchItems[id];
            if (oldItem.type === action.groupType) {
              newItems[id] = { ...oldItem, checked: id === action.id };
            } else {
              newItems[id] = oldItem;
            }
            return newItems;
          }, {})
        }
      };
  }
  return state;
}

如果您使用combineReducers并为您的searchItems创建一个reducer,这将变得更简单。lodash也可以简化:

import mapValues from 'lodash/mapValues';
function searchItemsReducer(state, action) {
  switch (action.type) {
    case 'FILTER_FLIGHT_OFFERS':
      return mapValues(state, (oldItem, id) => (
        oldItem.type === action.groupType 
          ? { ...oldItem, checked: id === action.id };
          : oldItem
      ));
  }
  return state;
}