Ngrx Effects调用API并与商店进行比较

问题描述 投票:1回答:2

所以我一直试图解决这一问题两天,而我放弃了,特别是在涉及到map系列时,rxjs非常棘手。

我有一个以MessageRequested为参数的动作id,该动作应启动api调用以获取消息,然后检查相应的访客是否在商店中。如果不在商店中,它将分派两个动作MessageLoadedVisitorRequested。如果在商店中,我们将只分派一个动作MessageLoaded。因此逻辑将按此顺序:

  1. [MessageRequested的发送是以id作为输入
  2. 现在我们以id作为参数调用api,我们返回了一个Message对象。消息定义如下。它具有visitor_id属性:mergeMap((action) => this.converseService.getMessage( action[0].message_id ))
  3. 现在查询商店,在visitor_id对象中的Message是否以“访客”状态(this.store.pipe(select(selectVisitorById( m.visitor_id ) ))存在
  4. 现在我们有一个if条件需要应用,

    a。如果select返回了某个内容,则表明访客已经在商店中,我们将仅返回MessageLoaded操作。

    b。如果select没有返回visitor,我们现在必须调度其他操作VisitorRequested以请求访问者。我们仍然需要调度MessageLoaded操作。因此,这就是2个动作。

现在输入代码:

    loadMessage$ = this.actions$
        .pipe(
            ofType<MessageRequested>(MessageActionTypes.MessageRequested),
            mergeMap((action) => this.converseService.getMessage( action[0].message_id )),
            map(m => m.model),
            withLatestFrom(  this.store.pipe(select(selectVisitorById( m.visitor_id ) ))),
            tap( ([message,visitor]) => {
                if (visitor == null) new VisitorRequested(message.visitor_id);
            }),
            map( ([message, visitor]) => {
                return new MessageLoaded({message});
            } )
        );
export class Message {
    id: number;
    message: string;
    visitor_id: number;
    is_from_visitor: boolean;
    created_at: string;
}

export class MessageResponse extends Response {
  model: Message
}

export class Response{
  message:String;
  didError: boolean;
  errorMessage: string;
}

代码看起来不错,除了withLatestFrom不接受输入,因此我无法传递m.visitor_id变量,现在我不得不考虑另一种方法。我尝试使用forkJoinconcatMap,但没有成功。

该方案中正确使用的运算符是什么?

更新#1

这是在所有答案的帮助下终于起作用的地方:

    @Effect()
    loadMessage$ = this.actions$
        .pipe(
            ofType<MessageRequested>(MessageActionTypes.MessageRequested),
            mergeMap((action) => this.converseService.getMessage( action.message_id )),
            map(m => m.model),
            concatMap(message =>
                of(message).pipe(
                  withLatestFrom(this.store.pipe(select(selectVisitorById(message.visitor_id))))
                )
            ),            
            tap( ([message,visitor]) => {
                if (!(visitor)) this.store.dispatch(new VisitorRequested(message.visitor_id));
            }),
            map( ([message, visitor]) => {
                return new MessageLoaded({message});
            } )
        );
angular rxjs ngrx ngrx-effects
2个回答
1
投票

tap不返回值,只是一个空值。而是根据条件返回一个动作数组:

 switchMap(([message,visitor]) => {
    if (visitor == null) return [new VisitorRequested(message.visitor_id), new MessageLoaded({message})];
    return [new MessageLoaded({message})]
 })

Imho,更正确的答案是产生两种效果:

1)收听MessageActionTypes.MessageRequested并调度MessageLoaded2)收听MessageActionTypes.MessageRequested,如果不在商店中,则调度VisitorRequested。甚至可以将VisitorRequested的逻辑设置为此效果。


0
投票

[如果您希望将存储中的某些数据与操作中的数据一起传递,则可以将映射函数传递给withLatestFrom()

someEffect$ = createEffect(() =>
        this.actions$.pipe(
            ofType(SOME_ACTION),
            withLatestFrom(this.store.select(yourFeature), (action, data) => ({ dataFromStore: data, payload: action.payload })),
            switchMap(props => {
                // do something fun
            })  
        )
    );

[如https://ngrx.io/guide/effects中所述,也建议将withLatestFrom包装在展平运算符中,因为withLatestFrom会立即通过select()进行侦听,而不管动作如何。

concatMap(action => of(action).pipe(
     withLatestFrom(this.store.pipe(select(yourFeature)))
))
© www.soinside.com 2019 - 2024. All rights reserved.