如何更改深层嵌套状态而不在操作中明确提供大量上下文?

时间:2016-02-06 13:43:42

标签: reactjs redux

我有几个级别嵌套的项目:

const initialState = {
  sections: [
    {
      name: 'Section 1',
      categories: [
        {
          name: 'Category 1',
          checklist: [
            { name: 'Item 1', checked: false },
            { name: 'Item 2', checked: true },
            { name: 'Item 3', checked: false },
          ]
        },
        // more categories
      ],
    },
    // more sections
  ],
};

我想知道是否有办法改变他们的状态(例如,切换checked属性)而不显式传递大量上下文:

function toggleCheckbox(sectionId, categoryId, itemId) {
  return {
    type: 'TOGGLE_CHECKBOX',
    sectionId: sectionId,
    categoryId: categoryId,
    itemId: itemId,
  };
}

function reducer(state = initialState, action) {    
  switch (action.type) {
    case 'TOGGLE_CHECKBOX':
      return Object.assign({}, state, {
        sections: state.sections.map(function (section, i) {
          return i === action.sectionId ? Object.assign({}, section, {
            categories: section.categories.map(function (category, j) {
              return j === action.categoryId ? Object.assign({}, category, {
                checklist: category.checklist.map(function (item, k) {
                  return k === action.itemId ? Object.assign({}, item, {
                    checked: !item.checked,
                  }) : item;
                }),
              }) : category;
            }),
          }) : section;
        }),
      });
    default:
      return state;
  }
}

随着部分,类别和清单的逻辑增长,我可能希望将它们作为单独的Reducer提取,但因为它们是嵌套的,所以我没有看到这样做的方法。

这里有一个bin,这个商店用React可视化。

我想我的问题有两部分:

  1. 如何将它们作为单独的Reducer提取?
  2. 如何避免明确提供如此多的上下文并避免所有真正只改变嵌套项目状态的映射?

1 个答案:

答案 0 :(得分:2)

嵌套对象肯定会很痛苦。 Dan对Redux docs中的嵌套实体有一点了解。

  

如果您有嵌套实体,或者您允许用户编辑收到   实体,你应该将它们分开保存在状态中,好像它是一个   数据库。在分页信息中,您只能通过它们来引用它们   他们的身份证这使您可以始终保持最新状态。

我已经修改了你的示例 jsbin 来进行演示,但它的要点包括将状态树稍微扁平一点。

const initialState = {
  sections: [
    {
      name: 'Section 1',
      categories: [ 'Category 1'],
    },
    // more sections
  ],
  categories: [
    {
      name: 'Category 1',
      checklist: ['Item 1', 'Item 2', 'Item 3']
    },
  ],
  items: [
    {
      name: 'Item 1',
      checked: false
    },
    {
      name: 'Item 2',
      checked: true
    },
    {
      name: 'Item 3',
      checked: false
    },
  ]

};

项目缩减器现在需要name才能知道要更新哪一个,而各个部分/类别会跟踪他们拥有哪些项目。现在,您可以拆分专用的类别,部分和项目缩减器,每个都可以处理他们自己关注的领域!

如果你想要在不同类别中使用相同名称的项目,你必须引入一个新ID以使它们彼此分开......但是现在使用名称是最简单的 < / p>