внедрение государственного управления в ngrx (Угловой)

#angular #typescript #ngrx

Вопрос:

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

  • Я пытаюсь вытащить имя и фамилию, dob, поля электронной почты и т. Д. Из магазина при загрузке
  • проверьте, не пусты ли какие-либо из этих полей
  • если есть пустое поле, я хочу знать, какое из полей пустое, с помощью проверки
  • если все поля заполнены, то разрешите доступ к следующему экрану Показывает поле, которым нужно управлять

Вот ссылка на мой stackblitz https://stackblitz.com/edit/angular-ivy-mesmpg?file=src/app/app.component.ts

-Вот мой класс моделей

 export interface GMT{
    data: GetGMTData;
    // isDataMissing: boolean;
    // listOfMissingData: [] | null;
}


export interface GetGMTData{
    firstAndLastName?: string;
    dateOfBirth?: string;
    emailAddress?: string;
    mobilePhone?: string;
    homeAddress?: string;
}
 

вот мой класс действий

 export const getGmtData = createAction('GET_GMT_DATA');

export const getGmtDataSuccess = createAction(
  'GET_GMT_DATA_SUCCESS',
  props<ResponseEntity<GetGMTData>>(),
);

export const getGmtDataFail = createAction('GET_GMT_DATA_FAIL', props<ResponseErrorEntity>());
 

вот мои редукторы

 export const globalTransfersStoreName = '/global-transfers';

export interface GlobalTransferInfoReviewDataState extends GMT {
  error?: ErrorMap | any;
  $api: ApiState;
}

export interface State extends AppState {
  [globalTransfersStoreName]: GlobalTransferInfoReviewDataState;
}

export const initialState: GlobalTransferInfoReviewDataState = {
  $api: {} as any,
  error: {},
  data: {},
  // isDataMissing: false,
  // listOfMissingData: [],
};

const GET_GMT_DATA = 'get_gmt_data';

export const globalTransferInfoReviewDataReducer = createReducer(
  initialState,
  on(gmtActions.getGmtData, (state: GlobalTransferInfoReviewDataState) => {
    return {
      ...state,
      $api: getApiState(state.$api, GET_GMT_DATA, API_STATUS.LOAD),
    } as GlobalTransferInfoReviewDataState;
  }),
  on(
    gmtActions.getGmtDataSuccess,
    (state: GlobalTransferInfoReviewDataState, action: ResponseEntity<GetGMTData>) =>
      ({
        ...state,
        data: action?.data,
        $api: getApiState(state.$api, GET_GMT_DATA, API_STATUS.SUCCESS),
      } as GlobalTransferInfoReviewDataState),
  ),
  on(
    gmtActions.getGmtDataFail,
    (state: GlobalTransferInfoReviewDataState, action: ResponseErrorEntity amp; TypedAction<string>) =>
      ({
        ...state,
        error: {
          ...state.error,
          [action.type]: action.validationErrors ? action.validationErrors[0] : action.error,
        },
        $api: getApiState(state.$api, GET_GMT_DATA, API_STATUS.ERROR),
      } as GlobalTransferInfoReviewDataState),
  ),
);
 

вот мои селекторы

 export const selectGmtState = createFeatureSelector<AppState, GlobalTransferInfoReviewDataState>(globalTransfersStoreName);
export const getApiState = createSelector(selectGmtState, (state: GlobalTransferInfoReviewDataState) => state.$api);
export const getEmtProfileState = createSelector(
    selectGmtState,
    (state: GlobalTransferInfoReviewDataState) => state.data,
  );
 

Комментарии:

1. Вопрос в том, как вы можете использовать все это в своем компоненте?

2. Да, это так? @Андрес2142. Мне также было интересно, нужно ли мне создавать класс effect.ts или service.ts

Ответ №1:

Здорово, что вы решили попробовать выучить NgRx. Это мощный инструмент, и при правильном использовании и в правильном проекте он принесет вам много преимуществ. Но для того, чтобы это произошло, есть некоторые правила, которым вы должны следовать. И вам удалось сломать сразу три из них, в основном нарушив основной принцип NgRx. И это:

1. Редукторы-это чистые функции

Это означает, что, предоставляя одни и те же входные данные, они будут возвращать одни и те же выходные данные. И у них нет побочных эффектов. Что, когда вы смотрите на свои редукторы, неприменимо.

2. Состояние должно быть сериализуемым

Это означает, что объект состояния должен быть предсказуемо сохранен в постоянном хранилище или передан по сети. Мы хотим, чтобы наше состояние NgRx было почти идентичным его представлению в формате JSON. И это не относится к вашим функциям, картам и наблюдаемым объектам в пределах штата.

3. Состояние должно быть предсказуемым

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

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

Государство

Удалите все, что не может быть сериализовано, в вашем случае Карту и этот API. Замените карту массивом объектов с ключевыми значениями, а API-интерфейс-реальным объектом ответа. Тот, который возвращает ваш API

 export interface GlobalTransferInfoReviewDataState extends GMT {
  error?: ErrorMap | any; // remove if it's really of type Map
  //$api: ApiState; - remove this, replace probably with GmtData
  gmdData: GmdData 
}

export const initialState: GlobalTransferInfoReviewDataState = {
  gmdData: null,
  error: {},
  data: {},
  isDataMissing: false,
  listOfMissingData: [],
};
 

Действия

Как только вы избавитесь от вредных элементов состояния, вы сможете обновить действия. Разделите их на действия, которые вызывают эффект, но не привязаны к ним. Позвольте эффекту волшебства, и как только все данные будут получены и обработаны, этот эффект не сможет отправить действие, которое приведет к срабатыванию редуктора.

 export const fetchGmtData = createAction('FETCH_GMT_DATA'); // have one action to fetch data from 3rd party something (API, JSON file, etc.)
export const saveGmtData = createAction('GET_GMT_DATA', props<{ gmtData: GmdData }>()); // and one to save them to the store
 

Эффекты

Теперь вы можете реализовать эффекты, которые будут прослушивать действия выборки, и они будут выполнять запрос и всю обработку данных. Как только они закончат, они смогут отправлять действия по сохранению.

 constructor (private gmtActions: GmtService) {} // Or something similar

getGmtData$ = createEffect(() =>
  this.actions$.pipe(
    ofType(gmtActions.getGmtData),
    concatMap(() => this.getApiState(state.$api, GET_GMT_DATA, API_STATUS.LOAD))
    map(gmtData => gmtActions.saveGmtData({ gmtData }))
  )
);
 

Редукторы

И чтобы завершить цепочку, реорганизуйте свои редукторы так, чтобы единственное, что они делали, — это создавали новое состояние с предоставленной полезной нагрузкой. Больше ничего, никаких побочных эффектов, никаких расчетов внутри. Чистые функции.

 on(gmtActions.saveGmtData, (state, { gmtData }) => ({
   ...state,
   gmtData
  })
),
 

Это путь NgRx. Таким образом, вы создали непредсказуемое управление состоянием с не сериализуемым состоянием. Это может сработать, но рано или поздно вы столкнетесь со странными проблемами, которые будет трудно исправить.