I have the following state structure:
{ 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)}
}
Now I just want to remove an item with the id '3' lets say.
The following does not work:
const state = ctx.getState();
delete state.entities[action.id];
ctx.setState(
patch<SportTypeStateModel>({
entities: {...state.entities},
IDs: state.IDs.filter(id => id !== action.id)
})
);
It throws the following error:
`ERROR TypeError: Cannot delete property '3' of [object Object]`
What is the right way of doing this?
First we need to understand why this error occurs.
NGXS uses deepFreeze
under the hood in the development mode to Object.freeze
your state (and deeply nested objects/arrays) to prevent unpredictable mutations.
You can check it up by calling Object.isFrozen
:
const state = ctx.getState();
console.log(Object.isFrozen(state.entities));
delete state.entities[action.id];
I understood your point that entities
is not an array, but an object.
So the problem is once an object has been frozen there is no way to unfreeze it. What do we have to do? We have to unfreeze the state object itself, the entities
object and its children:
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 do not like this code so don't throw stones at me :) I think you can search for some packages like deep-unfreeze
to be more declarative. Oh, I forgot about the IDs
property. The final code is:
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. checked it locally.