如何从标准化状态 delete/remove 一个项目?
How to delete/remove an item from normalized state?
我有以下状态结构:
{ 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]`
正确的做法是什么?
您可以过滤使用而不是删除;
newEntities = state.entities.filter(item => item.id !== action.id);
ctx.setState(
patch<SportTypeStateModel>({
entities: {...newEntities },
IDs: state.IDs.filter(id => id !== action.id)
})
);
最简单的方法就是过滤现有状态和补丁。
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
值,您不需要维护两个列表。
首先我们需要了解为什么会出现这个错误。
NGXS 在开发模式下使用 deepFreeze
来 Object.freeze
您的状态(并且深度嵌套 objects/arrays)以防止不可预测的突变。
您可以拨打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。在本地检查过。
我有以下状态结构:
{ 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]`
正确的做法是什么?
您可以过滤使用而不是删除;
newEntities = state.entities.filter(item => item.id !== action.id);
ctx.setState(
patch<SportTypeStateModel>({
entities: {...newEntities },
IDs: state.IDs.filter(id => id !== action.id)
})
);
最简单的方法就是过滤现有状态和补丁。
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
值,您不需要维护两个列表。
首先我们需要了解为什么会出现这个错误。
NGXS 在开发模式下使用 deepFreeze
来 Object.freeze
您的状态(并且深度嵌套 objects/arrays)以防止不可预测的突变。
您可以拨打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。在本地检查过。