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

问题描述

减速器:

list_of_str = ["Em","Bsus4","F7","Fis7"]
print([item[0:2] if len(item)>1 and item[1] == "m" else item[0:3] if len(item)>2 and item[1:3] == "is" else item[0] for item in list_of_str])

效果

['Em','B','F','Fis']

component.ts:

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
        }
      }  
    }
}

单击该方法,将调度一个动作,然后执行一个效果,我的情况是api调用是成功的,并且还调度了一个成功动作(在我的reducer中,我将标志设置为true),从click方法调度的AddUser操作,如果API返回成功响应,我正在订阅标志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 }))) ) ) ) ); 以将用户导航到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,我确实有其他功能可以处理,因此必须在组件中完成所有操作。

解决方法

事件的顺序如下:

  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. 您通过管道中的getUser运算符订阅了take(1)选择器
  this.store.pipe(select(getUser),take(1)).subscribe((isUserAdded) => {
    if(isUserAdded) {
      this.router.navigateByUrl('/success');
    } else {
      this.router.navigateByUrl('/home');
    }
  });
  1. 选择器从存储区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');
    }
  });
,

您是否不能只在您的效果fn中返回两个动作,例如UserAddedSuccess并在catchError UserAddedFail中编写另一个效果,该效果将侦听useraddedsuccess动作并在成功后重定向所需的页面,就第一个效果catcherror返回UserAddedFail动作和相同的过程吗?

,

我想您可以调度多个动作,您必须创建单独的动作来处理路由

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');
          ])
        )
      )
    )
  );