javascript - @ngrx/data - 撤消乐观删除,UNDO_ONE 操作是否应该恢复 changeState?
问题描述
堆栈闪电战
在@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() 方法的数据和选项的不同值:
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
应该恢复到{}
因为我们正在取消删除。
解决方案
根据此处的文档,它应该:
撤消操作根据 changeState 映射中的信息替换集合中的实体,将它们恢复为最后一个已知的服务器端状态,并将它们从 changeState 映射中删除。这些实体变得“不变”。
为了克服这个问题,您可以创建一个 metaReducer,它在撤消操作后删除 changeState 中剩余的相关修改。这是我的 entity-metadata.ts 的内容以及相关的 metareduce。
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。
推荐阅读
- python - Python pandas员工层次递归函数
- python - 模拟反斜杠键盘击键
- python - Django static files cannot find the path specified
- javascript - 根据属性值在 Map 中查找元素
- vba - 从活动工作表而不是特定工作表获取图表值
- php - 301 重定向标头语法
- javascript - JS中的射线/矩形相交
- java - 使用 JSOUP 从 URL 获取实际页面和最后一页
- c# - 如果 Json 变量在 WCF 中包含空格或任何特殊字符,如何获取 Json 值
- python - 绘制一个将输入作为框大小的框