@ ngrx / data - Отмена удаления optimisti c, должно ли действие UNDO_ONE вернуть changeState? - PullRequest
1 голос
/ 30 января 2020

Stackblitz

В @ ngrx / data, выполняющих оптимистическое c удаление (нашего героя "Человек-муравей"), вызывает изменение 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
          }
        }
      }
    }
  }
}

Используя приведенный ниже эффект, я вызвал UNDO_ONE, когда удаление завершилось неудачно из-за ошибки http-запроса:

  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>

Здесь я выполняю удаление * optimisti c и команду SAVE_DELETE_ONE_ERROR, отправляя действие UNDO_ONE через эффект.

Когда я заменяю UNDO_ONE на UNDO_ALL changeState возвращается обратно к {}, что дает мне основание думать, что changeState должно вернуться к {}, если мы отменяем удаление .

1 Ответ

1 голос
/ 04 февраля 2020

Согласно документации здесь , оно должно:

Операции отмены заменяют сущности в коллекции на основе информации в карте changeState, возвращая им их последний известный сервер- боковое состояние, и удаление их из карты changeState . Эти объекты становятся «неизменными».

Чтобы преодолеть эту проблему, вы можете создать метаредуктор, который удаляет соответствующие изменения, оставшиеся в changeState после отмены действия. Вот содержимое моего объекта-metadata.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
};

Возможно, есть лучший способ написания этого кода (в частности, способ, которым я обработал свойство override changeState), но для моего случая это оказалось работающим.

Кроме того, могут потребоваться некоторые обновления для обработки различных случаев отмены, поскольку, когда я писал его, мне просто нужно было заставить его работать для отмены, касающейся действия удаления, где action.payload.data - это идентификатор объекта.

...