如何显示成功消息 NgRX Effects 和调度事件

How to display a success message NgRX Effects and dispatch events

减速器:

export const reducer = (state = initialstate, action: any) => {
  switch (action.type) {
    case ADD_USER: {
      return {
        ...state,
        userAdded: false
        }
      },
    case ADD_USER_SUCCESS: {
      return {
        ...state,
        user: action.payload
        userAdded: true
        }
      },
    case ADD_USER_FAIL: {
      return {
        ...state,
        userAdded: false
        }
      }  
    }
}

效果:

login$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UserAction.ADD_USER),
      exhaustMap(action =>
        this.userService.addUser("USER").pipe(
          map(user => UserAction.AddUserSuccess({ "user" })),
          catchError(error => of(UserAction.AddUserFail({ error })))
        )
      )
    )
  );

component.ts:

onClickAddUser(): void {
  this.store.dispatch(new AddUser('USER'));
  this.store.pipe(select(getUser), take(1)).subscribe((isUserAdded) => {
    if(isUserAdded) {
      this.router.navigateByUrl('/success'); // Expectation is to navigate to success page
    } else {
      this.router.navigateByUrl('/home'); // for first time it's always going to home screen even the success action being dispatched and the value been set to true.
    }
  });
}

点击该方法,一个动作被分派并跟进一个效果,我的情况是 api 调用成功并且一个成功的动作也被分派(在我的减速器中我设置了一个标志true),在从 click 方法发送 AddUser 操作之后,如果 API return,我订阅标志 (isUserAdded) 以将用户导航到 /success 屏幕成功响应,在我的例子中,当我订阅标志时,它没有在商店中更新,因此用户导航到主屏幕(但期望是导航到成功屏幕,因为 API 是成功的) .是否可以等待商店中的值更新然后订阅它,或者是否有任何最佳实践来处理这种情况??

一旦成功操作被分派,我可以编写一个效果来导航用户,但我的意思是,一旦标志设置为真,我确实有其他功能要处理,因此必须在组件中执行所有操作。

你不能只 return 在你的效果 fn 中像 UserAddedSuccess 和 catchError UserAddedFail 写另一个效果,它将监听 useraddedsuccess 动作并在成功时重定向所需的页面,在第一个效果 catcherror return UserAddedFail 操作和相同的过程?

事件顺序如下:

  1. 你发送一个 AddUser 动作
this.store.dispatch(new AddUser('USER'));
  1. Reducer 被调用,状态被改变并且 userAdded 被设置为 false
    case ADD_USER: {
      return {
        ...state,
        userAdded: false
        }
      },
  1. 调用选择器并通知订阅者,但您还没有任何订阅
  2. 效果 ADD_USER 被调用,异步请求被发送到 userService
login$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UserAction.ADD_USER),
      exhaustMap(action =>
        this.userService.addUser("USER").pipe(
          map(user => UserAction.AddUserSuccess({ "user" })),
          catchError(error => of(UserAction.AddUserFail({ error })))
        )
      )
    )
  );
  1. 您在管道中使用 take(1) 运算符订阅了 getUser 选择器
  this.store.pipe(select(getUser), take(1)).subscribe((isUserAdded) => {
    if(isUserAdded) {
      this.router.navigateByUrl('/success');
    } else {
      this.router.navigateByUrl('/home');
    }
  });
  1. 选择器 returns 来自商店的 userAdded 标志的值为 false,您的回调函数被调用,订阅被 take(1) 操作员取消
  2. 路由器导航到“/home”
  3. 来自 userService 的回复被返回并且 userAdded 标志设置为 true 但您的订阅已经取消

如果您想要 component.ts 中的简单解决方案,只需尝试订阅 take(2), skip(1):

  this.store.pipe(select(getUser), take(2), skip(1)).subscribe((isUserAdded) => {
    if(isUserAdded) {
      this.router.navigateByUrl('/success');
    } else {
      this.router.navigateByUrl('/home');
    }
  });

我想你可以 dispatch 多个动作,你必须创建单独的 action 来处理 routing.

login$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UserAction.ADD_USER),
      exhaustMap(action =>
        this.userService.addUser("USER").pipe(
          switchMap(user => [
            UserAction.AddUserSuccess({ "user" }),
            routeAction.routeto('success')
          ])
          ,catchError(error => [
            UserAction.AddUserFail({ error }),
            routeAction.routeto('Home');
          ])
        )
      )
    )
  );