Stackblitz
在@ngrx/数据中,执行乐观删除(我们的英雄"蚁人"(会导致更改状态更新,如下所示:
{
"entityCache": {
"Hero": {
"ids": [1, 2, 3, 5, 6],
"entities": {
"1": {
"id": 1,
"name": "Spiderman",
"power": 1
},
"2": {
"id": 2,
"name": "Thor",
"power": 5
},
"3": {
"id": 3,
"name": "Hulk",
"power": 6
},
"5": {
"id": 5,
"name": "Iron Man",
"power": 9
},
"6": {
"id": 6,
"name": "Thanos",
"power": 10
}
},
"entityName": "Hero",
"filter": "",
"loaded": true,
"loading": true,
"changeState": {
"4": {
"changeType": 2,
"originalValue": {
"id": 4,
"name": "Ant-Man",
"power": 7
}
}
}
}
}
}
使用下面的效果,我在由于 http 请求错误导致删除失败时触发了一个UNDO_ONE:
deleteError$ = createEffect(() => {
return this.actions$.pipe(
ofEntityType("Hero"),
ofEntityOp([EntityOp.SAVE_DELETE_ONE_ERROR]),
map(action => {
const id = action.payload.data.originalAction.payload.data;
const options: EntityActionOptions = {
// tried various values
}
return new EntityActionFactory().create( <-----------------------dispatch UNDO_ONE action-----------
"Hero",
EntityOp.UNDO_ONE,
id,
options
);
})
);
});
问题:调度UNDO_ONE操作是否应还原changeState
即删除操作引起的对实体状态的这一部分的更改?
如果是这样,您如何正确调度UNDO_ONE以及需要哪些参数?
我已经探索了 EntityActionFactory.create(( 方法的数据和选项的不同值:
EntityActionFactory.create<P = any>(entityName: string, entityOp: EntityOp, data?: P, options?: EntityActionOptions): EntityAction<P>
在这里,我正在执行乐观删除,并在SAVE_DELETE_ONE_ERROR通过效果调度UNDO_ONE操作。
当我将UNDO_ONE换成UNDO_ALLchangeState
确实会恢复到{}
这让我有理由认为changeState
应该恢复到{}
,因为我们取消了删除。
根据这里的文档,它应该:
撤消操作根据 changeState 映射中的信息替换集合中的实体,还原其上一个已知的服务器端状态,并将它们从 changeState 映射中删除。这些实体变得"不变"。
为了克服这个问题,您可以创建一个metaReduce,该缩减器在撤消操作后删除更改状态中剩余的相关修改。这是我的实体元数据.ts的内容与相关的元化简器。
import { EntityMetadataMap, EntityDataModuleConfig, EntityCache } from '@ngrx/data';
import { MetaReducer, ActionReducer, Action } from '@ngrx/store';
const entityMetadata: EntityMetadataMap = {};
const pluralNames = {};
const objectWithoutProperties = (obj, keys) => {
const target = {};
for (const i in obj) {
if (keys.indexOf(i) >= 0) { continue; }
if (!Object.prototype.hasOwnProperty.call(obj, i)) { continue; }
target[i] = obj[i];
}
return target;
};
function revertStateChanges(reducer: ActionReducer<any>): ActionReducer<any> {
return (state, action: any) => {
if (action.type.includes('@ngrx/data/undo-one')) {
// Note that you need to execute the reducer first if you have an effect to add back a failed removal
state = reducer(state, action);
const updatedChangeState = objectWithoutProperties(state[action.payload.entityName].changeState, [action.payload.data.toString()]);
const updatedState = {
...state,
[action.payload.entityName]: {
...state[action.payload.entityName],
changeState: updatedChangeState
}
};
return reducer(updatedState, action);
}
return reducer(state, action);
};
}
const entityCacheMetaReducers: MetaReducer<EntityCache, Action>[] = [revertStateChanges];
export const entityConfig: EntityDataModuleConfig = {
entityMetadata,
pluralNames,
entityCacheMetaReducers
};
可能有更好的方法来编写此代码(特别是我处理覆盖 changeState 属性的方式(,但就我而言,它被证明是有效的。
此外,它可能需要一些更新来处理不同的撤消情况,因为当我编写它时,我只需要让它用于有关删除操作的撤消,其中 action.payload.data 是实体 ID。