#angular #typescript #rxjs #ngrx
Вопрос:
Короче говоря, я младший разработчик .Net, и я получил задание изменить что-то в нашем приложении Angular, я понятия не имею, как это работает, и я изо всех сил пытаюсь это изменить. Я застрял на одной теме.
Пользователь создается на основе формы, после ее заполнения происходит вызов:
submit() {
if (this.accountForm.invalid) {
return;
}
const {
email,
accountExpirationDate,
firstName,
lastName,
permissionLevel,
timezone,
language,
} = this.accountForm.value;
const accountExpirationDateMs = new Date(accountExpirationDate || null).getTime();
const result = {
email,
accountExpirationDate: accountExpirationDateMs || null,
name: firstName,
lastName,
roleExternalIds: [permissionLevel],
timezone,
languageExternalId: language,
avatar: this.avatar
};
if (!this.id) {
this.store.dispatch(fromUser.createUserAction({ result } as any));
} else {
this.isPending = true;
this.store.dispatch(fromUser.editUserAction({ result, id: this.id } as any));
setTimeout(() => {
this.store.dispatch(fromSettings.getCurrentUserInfoAction());
}, 1200);
}
}
После this.store.dispatch(fromUser.createUserAction({ result } as any));
инструкции if я должен сделать еще два вызова, которые требуют, чтобы я предоставил идентификатор пользователя, который возвращается бэкэндом после создания пользователя, но я понятия не имею, как извлечь его из этого вызова.
Действие Создать пользователя выглядит следующим образом:
export const createUserAction = createAction('[User management] Create User', props<{result: UserRegistrationRequestModel}>());
И я верю, что он делает этот звонок:
createUser$ = createEffect(() =>
this.actions$.pipe(
ofType(fromUserManagement.createUserAction),
mergeMap((action) => {
return this.identityServiceClient.create(action.result).pipe(
map(response => {
this.messageService.open('User has been created!', 'success');
this.router.navigateByUrl('/app/users/list');
return fromUserManagement.createUserActionSuccess(response)
}),
catchError(() => {
this.messageService.open('Something went wrong!', 'danger');
return fromUserManagement.createUserActionError;
})
);
})
)
)
Это может быть глупый вопрос с недостаточным количеством информации, но я использую angular впервые в своей жизни, так что, честно говоря, я понятия не имею, как это работает 😀
Ответ №1:
Вы можете dispatch
создать новое действие из своего createUser$
эффекта, чтобы выполнить дополнительную работу, и передать в нем необходимые параметры. Затем вы можете создать новый effect
для обработки новых отправленных action
и вызывать все, что захотите внутри.
Или, если вы хотите обработать его таким же effect
образом после получения результата от identityServiceClient.create
функции, вы можете попробовать что-то вроде следующего:
createUser$ = createEffect(() =>
this.actions$.pipe(
ofType(fromUserManagement.createUserAction),
mergeMap((action) => {
return this.identityServiceClient.create(action.result).pipe(
map((response) => {
this.messageService.open('User has been created!', 'success');
this.router.navigateByUrl('/app/users/list');
}),
switchMap((response) =>
// Call here all the extra requests (request1$, request2$) depending on the response,
// and the `forkJoin` will emit the value once all the request have been completed
forkJoin({ response1: request1$, response2: request2$ }).pipe(
// if you want to do extra work with the results that come from request1$ amp; request2$ you can do it here using `tap` operator
tap(({ response1, response2 }) => console.log(response1, response2)),
// and after that you need to return back the action you want to dispatch which is `createUserActionSuccess` in your case
map(() => fromUserManagement.createUserActionSuccess(response))
)
),
catchError(() => {
this.messageService.open('Something went wrong!', 'danger');
return fromUserManagement.createUserActionError;
})
);
})
)
);
Ответ №2:
Для краткого ознакомления с тем, с чем вы работаете, похоже, что в ваших кодовых базах используется NgRx для управления состоянием. Действия, которые вы видите отправляемыми, задокументированы здесь. Аналогично, эффекты задокументированы здесь. С этим изображением можно суммировать весь жизненный цикл взаимодействия:
https://user-images.githubusercontent.com/3605268/61837742-1851a300-ae54-11e9-97ed-9fb862d0bbf8.png
Приведенный выше ответ, безусловно, является решением, это просто зависит от того, что вам нужно сделать с идентификатором пользователя после создания пользователя. Когда действия отправляются в NgRx, ожидается, что какой бы объект ни выполнял отправку, он запустил это действие и вообще не ожидает возвращаемого значения ( userId
в вашем случае).
Похоже, что если пользователь уже существует, вы просто запрашиваете данные пользователя в API. Итак, если это так, то я бы создал эффект, который прослушивает успешное создание пользователя ( fromUserManagement.createUserActionSuccess
), а затем запускает то же самое действие, уже упомянутое для запроса ( fromSettings.getCurrentUserInfoAction
) :
updateUserAfterCreation$ = createEffect(() =>
this.actions$.pipe(
ofType(fromUserManagement.createUserActionSuccess),
switchMap((action) =>
fromSettings.getCurrentUserInfoAction()
)
)
);
В приведенном выше примере я предполагаю, что диспетчеризация fromSettings.getCurrentUserInfoAction
запускает эффект, который уже есть в вашей кодовой базе, и использует любые userId
уже сохраненные в хранилище (поскольку getCurrentUserInfoAction
не принимает никаких параметров, таких как userId
).
Этот шаблон можно повторить для любого конкретного случая использования — если вам поручено обновить профиль пользователя сразу после создания, то вместо указания switchMap
на fromSettings.getCurrentUserInfoAction
вы могли бы использовать fromSettings.updateNewUserAction
. Лично я предпочитаю отделять эти цепочки эффектов вместо того, чтобы помещать их в один большой канал в предыдущем ответе — это проще тестировать, легче читать и легче устранять неполадки.