在@ ngrx / data中,对(我们的英雄“蚂蚁人”进行了乐观删除)导致changeState如下所示进行更新:
{
"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() method的数据和选项探索了不同的值:
EntityActionFactory.create<P = any>(entityName: string, entityOp: EntityOp, data?: P, options?: EntityActionOptions): EntityAction<P>
这里我正在进行乐观删除,并在SAVE_DELETE_ONE_ERROR上通过效果调度UNDO_ONE操作。
[当我将UNDO_ONE换成UNDO_ALL时,changeState
确实恢复为{}
,这使我有理由认为changeState
应该恢复为{}
,因为我们要取消删除。
根据文档here,它应该:
撤消操作根据changeState映射中的信息替换集合中的实体,还原它们的最后一个已知的服务器端状态,并从changeState映射中将其删除。这些实体变为“不变”。
为了克服此问题,您可以创建一个metaReducer,该撤消操作将在撤消操作后删除changeState中剩余的相关修改。这是我的实体metadata.ts和相关的metareducer的内容。
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。