在 @ngrx/effects 中的 http 调用之前调度操作

Dispatch action before http call in @ngrx/effects

我想使用 rxjs 的效果进行 http 调用。现在我的问题是我想在 http 调用之前分派另一个动作,例如 { type: LoaderActions.LOADER_START } 。因此,用户可以在请求 Http 调用时看到加载屏幕,一旦请求完成,我想分派另一个操作 { type: LoaderActions.LOADER_END }

如何使用 rxjs 运算符实现此目的?我很困惑什么时候在 rxjs 中使用哪个运算符。

auth.effects.ts

import { Injectable } from '@angular/core';
import { Observable, of, concat } from 'rxjs';
import { Action, Store } from '@ngrx/store';
import { Actions, Effect, ofType } from '@ngrx/effects';
import * as AuthActions from './auth.actions';
import * as LoaderActions from '../../loader/store/loader.actions';
import {
  map,
  mergeMap,
  switchMap,
  debounce,
  debounceTime,
  tap,
  startWith
} from 'rxjs/operators';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Router } from '@angular/router';
const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json; charset=utf-8'
  })
};
@Injectable()
export class AuthEffects {
  @Effect()
  signInAction$: Observable<Action> = this.actions$.pipe(
    ofType(AuthActions.TRY_SIGN_IN),
    mergeMap(action =>
      this.http
        .post(
          'http://localhost:8081/auth',
          JSON.stringify({
            username: action['username'],
            password: action['password']
          }),
          httpOptions
        )
        .pipe(
          map(data => {
            if (data['message'] === 'successs') {
              this.router.navigate(['/todo']);
              return { type: AuthActions.SET_AUTH_FLAG, payload: true };
            } else {
              return { type: AuthActions.SET_AUTH_FLAG, payload: false };
            }
          })
        )
    )
  );

  constructor(
    private actions$: Actions,
    private http: HttpClient,
    private router: Router
  ) {}
}

您应该为 ofType(AuthActions.TRY_SIGN_IN) 创建更多效果侦听器并将此操作映射到发出 { type: LoaderActions.LOADER_START }。然后,在你提供的效果中,你应该

switchMap(data => {
            if (data['message'] === 'successs') {
              this.router.navigate(['/todo']);
              return [{ type: AuthActions.SET_AUTH_FLAG, payload: true }, { type: LoaderActions.LOADER_END }];
            } else {
              return [{ type: AuthActions.SET_AUTH_FLAG, payload: false }, { type: LoaderActions.LOADER_END }];
            }
          })

通过这种方法,您将获得所需的行为: 加载器操作和 http 请求同时执行,当 http 请求完成时,它将发出设置 auth 标志和删除加载器的操作

您可以使用 concat,其中第一个源 Observable 将作为加载操作。

@Effect()
signInAction$: Observable<Action> = this.actions$.pipe(
  ofType(AuthActions.TRY_SIGN_IN),
  concatMap(action => concat(
    of({ type: LoaderActions.LOADER_START }),
    this.http...
    of({ type: LoaderActions.LOADER_END }),
  ))
)

concat 操作员将确保按顺序创建操作。

你不应该为了你的目的而使用额外的动作。只需在您的状态中添加一个 loading: boolean 属性 并默认设置为 false 即可。当你发送 TRY_SIGN_IN 时,你可以在 reducer 中将它设置为 true。当 http 成功或失败到达时,您可以通过调度 SET_AUTH_FLAG 操作再次将加载状态设置为 false。

然后您可以 select 使用适当的 select 加载状态,但我想您知道我的意思,并在您的模板中将其与 Angulars async 管道一起使用。