API вызова Ngrx Effects и сравнение с магазином - PullRequest
1 голос
/ 07 октября 2019

Итак, я пытался понять это в течение 2 дней, и я сдался, rxjs очень сложен, особенно когда речь идет о семействе map.

У меня есть действие MessageRequested с параметром id, которое должно инициировать вызов API для получения сообщения, а затем проверить, находится ли соответствующий посетитель в магазине или нет. Если его нет в магазине, он отправит два действия, MessageLoaded и VisitorRequested. Если он находится в магазине, мы просто отправим одно действие MessageLoaded. Таким образом, логика будет в следующем порядке:

  1. MessageRequested было отправлено с id в качестве входа
  2. Теперь мы вызываем API с id в качестве параметра, мывернул 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, и теперь мне нужно подумать о другом подходе. Я пытался использовать forkJoin и concatMap, но не сделал этого.

Какие правильные операторы использовать в сценарии?

Обновление # 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});
            } )
        );

Ответы [ 2 ]

1 голос
/ 07 октября 2019

tap не возвращает значение, это просто пустота. Вместо этого верните массив действий в зависимости от условия:

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

Имхо, более правильный ответ будет иметь 2 эффекта:

1) прослушивание MessageActionTypes.MessageRequested и диспетчеризация MessageLoaded 2) прослушайте MessageActionTypes.MessageRequested и отправьте VisitorRequested, если его нет в магазине. Или даже, поместите логику VisitorRequested в этот эффект.

0 голосов
/ 07 октября 2019

Если вы хотите передать некоторые данные из хранилища вместе с данными из действия, вы можете передать функцию карты в 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,также рекомендуется переносить с помощью LastFrom в операторе выравнивания, поскольку withLatestFrom будет прослушивать select() сразу, независимо от входящего действия.

concatMap(action => of(action).pipe(
     withLatestFrom(this.store.pipe(select(yourFeature)))
))
...