Как удалить / удалить элемент из нормализованного состояния? - PullRequest
0 голосов
/ 11 ноября 2019

У меня следующая структура состояний:

{ 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)}
}

Теперь я просто хочу удалить элемент с идентификатором '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 голосов
/ 11 ноября 2019

Простейшим способом было бы просто отфильтровать существующее состояние и патч.

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, и вам не нужно поддерживать два списка.

0 голосов
/ 11 ноября 2019

Сначала нам нужно понять, почему возникает эта ошибка.

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];

Мне не нравится этот код, поэтому не бросайте в меня камни:) IЯ думаю, что вы можете искать некоторые пакеты, например 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;
});

PS проверил его локально.

0 голосов
/ 11 ноября 2019

Вы можете использовать фильтр вместо удаления;

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

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