所以我一直试图解决这一问题两天,而我放弃了,特别是在涉及到map
系列时,rxjs非常棘手。
我有一个以MessageRequested
为参数的动作id
,该动作应启动api调用以获取消息,然后检查相应的访客是否在商店中。如果不在商店中,它将分派两个动作MessageLoaded
和VisitorRequested
。如果在商店中,我们将只分派一个动作MessageLoaded
。因此逻辑将按此顺序:
MessageRequested
的发送是以id
作为输入id
作为参数调用api,我们返回了一个Message
对象。消息定义如下。它具有visitor_id
属性:mergeMap((action) => this.converseService.getMessage( action[0].message_id ))
visitor_id
对象中的Message
是否以“访客”状态(this.store.pipe(select(selectVisitorById( m.visitor_id ) )
)存在现在我们有一个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
变量,现在我不得不考虑另一种方法。我尝试使用forkJoin
和concatMap
,但没有成功。
该方案中正确使用的运算符是什么?
这是在所有答案的帮助下终于起作用的地方:
@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});
} )
);
tap
不返回值,只是一个空值。而是根据条件返回一个动作数组:
switchMap(([message,visitor]) => {
if (visitor == null) return [new VisitorRequested(message.visitor_id), new MessageLoaded({message})];
return [new MessageLoaded({message})]
})
Imho,更正确的答案是产生两种效果:
1)收听MessageActionTypes.MessageRequested
并调度MessageLoaded
2)收听MessageActionTypes.MessageRequested
,如果不在商店中,则调度VisitorRequested
。甚至可以将VisitorRequested
的逻辑设置为此效果。
[如果您希望将存储中的某些数据与操作中的数据一起传递,则可以将映射函数传递给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)))
))