NgRx:在单个效果中调度多个操作

问题描述 投票:0回答:6

我需要在调用 API 请求后分派多个操作。 我目前正在使用此代码在 API 请求完成后分派一个操作:

 changeStatus$ = createEffect(() => 
  this.actions$.pipe(
    ofType(fromJtDetail.changeStatus),
    switchMap(action =>
      this.jtDetailService.changeStatus(action.entity,action.jobTicketId).pipe(
        map(res => fromJtDetail.statusChanged({changedStatus: action.entity.newStatus})),
        catchError(error => EMPTY)
))));

在此效果中调度更多动作非常重要,无法为此编写其他效果。

angular rxjs ngrx ngrx-effects
6个回答
31
投票

您可以使用

switchMap
+
of(

分派多个操作
changeStatus$ = createEffect(() => 
  this.actions$.pipe(
    ofType(fromJtDetail.changeStatus),
    switchMap(action =>
      this.jtDetailService.changeStatus(action.entity,action.jobTicketId).pipe(
      switchMap(res => of(
        fromJtDetail.statusChanged({changedStatus: action.entity.newStatus}),
        fromHere.doSmthAction(),      // <-- additional action 1
        fromThere.doSmthElseAction(), // <-- additional action 2
      )),
      catchError(error => EMPTY)
))));

编辑:
虽然可以做,但你不应该这样做。
看一下 无多重操作效果


14
投票

这里的所有答案都是正确的,“简单”的答案和解决方案是返回一组操作。然而,这是一种不好的做法,有关更多信息,请参阅 NgRx ESLint 文档中的No Multiple Actions In Effects


3
投票

您可以将操作数组传递到 switchMap 中,如下所示:

switchMap(result => ([new Action1(result), new Action2(result)])

3
投票

这个答案可能对其他寻求解决多个操作效果的人有帮助。

正如其他人已经回答的那样,

  1. 您可以在一个效果中调度多个动作(返回动作数组,或使用存储来调度(this.store.dispatch(otherAction()) - 但不行!

  2. 您不应该在一个效果中分派多个操作,因为它是反模式(https://github.com/timdeschryver/eslint-plugin-ngrx/blob/main/docs/rules/no-multiple-actions-in -效果.md

解决方案:效果链接(一种效果触发另一种效果)

updateAPILoadingState$ = createEffect(()=>{
 return this.action$.pipe(

 ofType(getAPIAction), // <-- same action which below effects uses to update loading status 

 exhaustMap(()=>{
     return updateLoadingState("LOADING")
          })
 )    
})

getSomeInformationFromAPI$ = createEffect(()=>{
return this.action$.pipe(

 ofType(getAPIAction), // <--- Listens to the Action

 exhaustMap(()=>{
     return this.apiService.getSomething().pipe(
                map((apiResponse)=>
                     postAPISuccess(apiResponse)) // <-- trigger action to save the response
          })
 )  
})

 postAPISuccessEffect$ = createEffect(()=>{
   return this.action$.pipe(

   ofType(postAPISuccess), // <--- EFFECTS CHAIN : listen to the action which was triggered by above effect

   exhaustMap(()=>{
     return updateLoadingState("LOADED")
   )  
})

1
投票

当然,其他答案公平地提到您可以使用注入的

Store
引用或
switchMap
来分派多个操作,但值得注意的是,这不被认为是一个特别好的做法,因为它在某些情况下可能会掩盖意图,并使其他影响(由此触发的影响)变得更难以推理。您可以在here找到如何克服这一问题的详细说明,但简单来说,一个效果应该只调度一个且仅一个操作,然后其他效果(或减速处理程序)也应该另外监听该一个操作。我提供的链接还提供了如何将代码更改为更正确版本的示例。


0
投票
private _getAllEntreprises = createEffect(() =>
    this.actions$.pipe(
      ofType(EntrepriseActions.getAllEnterprises),
      switchMap(({ query, page }) =>
        this.service
          .getAllEntreprises(page, query)
          .pipe(
            exhaustMap
            ((response) => {
   
              return[
                EntrepriseActions.getCurrentPage({current:response.current_page}),
                EntrepriseActions.getTotalPages({ total: response.total_pages }),
                EntrepriseActions.getAllEnterprisesCompleted({entreprises:response.enterprises}),
                SettingsActions.loading({ loading: false }),
                SettingsActions.successMsg({ message: response.message }),
            ]})
          )
      )
    )
  );
© www.soinside.com 2019 - 2024. All rights reserved.