@@ ngrx / data-撤消乐观删除,UNDO_ONE操作是否应还原changeState?

问题描述 投票:1回答:1

Stackblitz

在@ 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应该恢复为{},因为我们要取消删除。

javascript angular ngrx ngrx-effects angular-ngrx-data
1个回答
1
投票

根据文档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。

© www.soinside.com 2019 - 2024. All rights reserved.