如何从规范化状态删除/删除项目?

时间:2019-11-11 03:02:24

标签: angular typescript redux ngxs

我具有以下状态结构:

{ entities:
1: {name: "Basketball", id: "1", leagues: Array(3)}
2: {name: "Volleyball", id: "2", leagues: Array(3)}
3: {name: "Soccer", id: "3", leagues: Array(0)}
}

现在我只想删除ID为'3'的商品。

以下内容无效:

const state = ctx.getState();
    delete state.entities[action.id];

    ctx.setState(
      patch<SportTypeStateModel>({
        entities: {...state.entities},
        IDs: state.IDs.filter(id => id !== action.id)
      })
    );

它引发以下错误:

`ERROR TypeError: Cannot delete property '3' of [object Object]`

正确的做法是什么?

3 个答案:

答案 0 :(得分:0)

您可以过滤使用而不是删除;

newEntities = state.entities.filter(item => item.id !== action.id);

ctx.setState(
      patch<SportTypeStateModel>({
        entities: {...newEntities },
        IDs: state.IDs.filter(id => id !== action.id)
      })
    );

答案 1 :(得分:0)

最简单的方法就是过滤现有状态和补丁。

const state = ctx.getState();
ctx.patchState({
  entities: [...state.entities.filter(e => e.id !== action.id)],
  IDs: [...state.IDs.filter(i => i !== action.id)]
}

您使用的状态模型未在此处列出-但是,如果您存储实体,则将IDs属性建模为@Selector而不是模型的一部分会更整洁。状态,因为它只是实体列表中内容的投影,例如

@Selector()
static IDs(state: YourStateModel) {
  return state.entities.map(e => e.id);
}

这意味着它始终基于当前的state.entites值,并且您不需要维护两个列表。

答案 2 :(得分:0)

首先,我们需要了解为什么会发生此错误。

NGXS在开发模式下使用deepFreeze Object.freeze来保护您的状态(以及深度嵌套的对象/数组),以防止发生不可预测的突变。

您可以通过致电Object.isFrozen进行检查:

const state = ctx.getState();
console.log(Object.isFrozen(state.entities));
delete state.entities[action.id];

我理解您的观点,entities不是数组,而是对象。

因此问题是,一旦冻结了对象,就无法解冻它。我们该做什么?我们必须解冻状态对象本身,entities对象及其子对象:

const state = ctx.getState();
const newState = { ...state, entities: { ...state.entities }};
for (const key of Object.keys(newState.entities)) {
  newState.entities[key] = { ...newState.entities[key] };
}
console.log(Object.isFrozen(newState.entities));
delete newState.entities[action.id];

我不喜欢此代码,所以请不要对我投掷石块:)我想您可以搜索一些deep-unfreeze之类的软件包,以提高声明性。哦,我忘记了IDs属性。最终的代码是:

ctx.setState(state => {
  const newState = {
    entities: { ...state.entities },
    IDs: state.IDs.filter(id => id !== action.id)
  };
  for (const key of Object.keys(newState.entities)) {
    newState.entities[key] = { ...newState.entities[key] };
  }
  delete newState.entities[action.id];
  return newState;
});

P.S。在本地检查。