#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. Таким образом, вы создали непредсказуемое управление состоянием с не сериализуемым состоянием. Это может сработать, но рано или поздно вы столкнетесь со странными проблемами, которые будет трудно исправить.