如何使用带参数的选择器从效果中的 ngrx 存储 select
how to select form ngrx store within an Effect using a slector with parameters
我需要构建一个 Effect 并且我需要一个来自商店的值,问题是选择器是一个带参数的选择器。
遵循示例代码:
@Effect()
ExampleEffect$ = this.actions$.pipe(
ofType(
ActionTypes.SOMETHING
),
map((action: Somthing) => action.payload.myParameter),
// HERE I NEED THE PARAMETER TO PERFROM THE SELECTION
withLatestFrom(this.store.pipe(select(selectorWithParamter(myParameter))),
map((value) => /* do somthing with the array [myParameter, valueSelected from sotre]*/)
您可以在创建选择器时编写一个箭头函数来传递参数。
export const getAlbumById = (collectionId: number) => createSelector(getAlbumEntities, entities => entities[collectionId]);
更多示例
//效果
@Effect({ dispatch: true })
upsertAlbum$ = this.actions$.pipe(
ofType(AlbumActionTypes.UpsertAlbum),
map((action: any) => action.payload),
mergeMap(({ album }) =>
this.store.pipe(
select(selectAlbumIfExists(album.id)),
first(),
map(isAlbumHasName => [album, isAlbumHasName])
)
),
filter(([album, isAlbumHasName]) => !isAlbumHasName),
map(([album]) => new LoadAlbum({ album }))
);
// 选择器
export const selectAlbumIfExists = (id: string) =>
createSelector(
selectAlbumsEntities,
entities => !!(entities[id] && entities[id].name)
);
为什么不使用 props
对象?
https://ngrx.io/guide/store/selectors#using-selectors-with-props
您可以创建特定的选择器并在调用 withLatestFrom
时使用它们。
approve$ = createEffect(() => {
return this.actions$.pipe(
ofType(myactions.approve),
withLatestFrom(this.store.select(selectReference), this.store.select(selectWork)),
switchMap(([_, reference, work]) => this.service.approve(reference, work)),
map(() => actions.approveSuccess())
);
});
按照上面的建议,尝试使用选择器。就我而言,
selectReference
和
selectWork
是 NGRX 选择器,代码如下所示:
//create slice
const requestState= createFeatureSelector<IRequestState>(feature);
//get exactly what you need from the state, not extra stuff
export const selectReference= createSelector(requestState, (state) => state?.reference);
export const selectWork= createSelector(requestState, (state) => state.Work);
保持干净,不要重复选择代码。我怀疑您是否需要带参数的选择器。尝试在选择器中获取列表并通过另一个选择器获取参数。在 switchMap 函数中执行逻辑(或者任何最适合你的函数,mergeMap 或 concatMap)
andreisrob
的建议很好。下面提供了一个完整的工作示例。这显示了效果如何使用需要参数的选择器中的值。
updateQuestionnaireTranslationValue$ = createEffect(() => this.actions$.pipe(
ofType(QuestionnaireTranslationsUpdateValueAction),
concatMap((action) => {
this.store.dispatch(GlobalLoadingStartedAction({ message: "Updating translation value ..."}));
const props = { formId: action.payload.formId, langId: action.payload.translationLanguageId};
const update$ = this.store.pipe(
select(selectQuestionnaireTranslationResourceCount, props),
first(),
concatMap(translatableCount => {
const updateRes$ = this.questionnaireService.updateTranslation(action.payload, translatableCount).pipe(
tap(() => this.store.dispatch(GlobalLoadingEndedAction())),
catchError(err => {
this.store.dispatch(GlobalLoadingEndedAction());
this.logger.logErrorMessage("Error updating translation value: " + err);
this.snackBar.openError("Failed to update translation value");
this.store.dispatch(QuestionnaireTranslationsUpdateValueCancelledAction());
return of(null);
})
);
return updateRes$;
})
);
return update$.pipe(map(count => ({ value: action.payload, totalCount: count } )));
}),
map((payload: ({ value: QuestionnaireTemplateTranslationUpdateValue, totalCount: number })) => {
return QuestionnaireTranslationsUpdateValueDoneAction({ payload });
}))
);
我需要构建一个 Effect 并且我需要一个来自商店的值,问题是选择器是一个带参数的选择器。
遵循示例代码:
@Effect()
ExampleEffect$ = this.actions$.pipe(
ofType(
ActionTypes.SOMETHING
),
map((action: Somthing) => action.payload.myParameter),
// HERE I NEED THE PARAMETER TO PERFROM THE SELECTION
withLatestFrom(this.store.pipe(select(selectorWithParamter(myParameter))),
map((value) => /* do somthing with the array [myParameter, valueSelected from sotre]*/)
您可以在创建选择器时编写一个箭头函数来传递参数。
export const getAlbumById = (collectionId: number) => createSelector(getAlbumEntities, entities => entities[collectionId]);
更多示例
//效果
@Effect({ dispatch: true })
upsertAlbum$ = this.actions$.pipe(
ofType(AlbumActionTypes.UpsertAlbum),
map((action: any) => action.payload),
mergeMap(({ album }) =>
this.store.pipe(
select(selectAlbumIfExists(album.id)),
first(),
map(isAlbumHasName => [album, isAlbumHasName])
)
),
filter(([album, isAlbumHasName]) => !isAlbumHasName),
map(([album]) => new LoadAlbum({ album }))
);
// 选择器
export const selectAlbumIfExists = (id: string) =>
createSelector(
selectAlbumsEntities,
entities => !!(entities[id] && entities[id].name)
);
为什么不使用 props
对象?
https://ngrx.io/guide/store/selectors#using-selectors-with-props
您可以创建特定的选择器并在调用 withLatestFrom
时使用它们。
approve$ = createEffect(() => {
return this.actions$.pipe(
ofType(myactions.approve),
withLatestFrom(this.store.select(selectReference), this.store.select(selectWork)),
switchMap(([_, reference, work]) => this.service.approve(reference, work)),
map(() => actions.approveSuccess())
);
});
按照上面的建议,尝试使用选择器。就我而言,
selectReference
和
selectWork
是 NGRX 选择器,代码如下所示:
//create slice
const requestState= createFeatureSelector<IRequestState>(feature);
//get exactly what you need from the state, not extra stuff
export const selectReference= createSelector(requestState, (state) => state?.reference);
export const selectWork= createSelector(requestState, (state) => state.Work);
保持干净,不要重复选择代码。我怀疑您是否需要带参数的选择器。尝试在选择器中获取列表并通过另一个选择器获取参数。在 switchMap 函数中执行逻辑(或者任何最适合你的函数,mergeMap 或 concatMap)
andreisrob
的建议很好。下面提供了一个完整的工作示例。这显示了效果如何使用需要参数的选择器中的值。
updateQuestionnaireTranslationValue$ = createEffect(() => this.actions$.pipe(
ofType(QuestionnaireTranslationsUpdateValueAction),
concatMap((action) => {
this.store.dispatch(GlobalLoadingStartedAction({ message: "Updating translation value ..."}));
const props = { formId: action.payload.formId, langId: action.payload.translationLanguageId};
const update$ = this.store.pipe(
select(selectQuestionnaireTranslationResourceCount, props),
first(),
concatMap(translatableCount => {
const updateRes$ = this.questionnaireService.updateTranslation(action.payload, translatableCount).pipe(
tap(() => this.store.dispatch(GlobalLoadingEndedAction())),
catchError(err => {
this.store.dispatch(GlobalLoadingEndedAction());
this.logger.logErrorMessage("Error updating translation value: " + err);
this.snackBar.openError("Failed to update translation value");
this.store.dispatch(QuestionnaireTranslationsUpdateValueCancelledAction());
return of(null);
})
);
return updateRes$;
})
);
return update$.pipe(map(count => ({ value: action.payload, totalCount: count } )));
}),
map((payload: ({ value: QuestionnaireTemplateTranslationUpdateValue, totalCount: number })) => {
return QuestionnaireTranslationsUpdateValueDoneAction({ payload });
}))
);