【问题标题】:NGRX: error populationNGRX:错误人口
【发布时间】:2017-03-11 21:23:43
【问题描述】:

我正在尝试使用 ngrx 填充网络/业务/任​​何类型的相关错误。为此,我在IStore 中添加了一个字段:

export interface IStore {
  user: IUser;
  sources: ISourceRedux;
  errors: IError;
}

如您所见,我正在使用这些 reducer 处理 user 状态:

export class UserReducer {
    private static reducerName = 'USER_REDUCER';

    public static reducer(user = initialUserState(), {type, payload}: Action) {
        if (typeof UserReducer.mapActionsToMethod[type] === 'undefined') {
            return user;
        }

        return UserReducer.mapActionsToMethod[type](user, type, payload);
    }

    public static USER_LOGIN = `${UserReducer.reducerName}_USER_LOGIN`;

    public static USER_LOGIN_SUCCESS = `${UserReducer.reducerName}_USER_LOGIN_SUCCESS`;
    private static userLoginSuccess(sourcesRdx, type, payload) {
        return Object.assign(<IUser>{}, sourcesRdx, payload);
    }

    public static USER_LOGIN_FAILED = `${UserReducer.reducerName}_USER_LOGIN_FAILED`;
    private static userLoginFailed(sourcesRdx, type, payload) {
        return Object.assign(<IUser>{}, sourcesRdx, payload);
    }

  private static mapActionsToMethod = {
      [UserReducer.USER_LOGIN_SUCCESS]: UserReducer.userLoginSuccess,
      [UserReducer.USER_LOGIN_FAILED]: UserReducer.userLoginFailed,
  };
}

USER_LOGIN 操作已完成,因为我设置了效果:

@Injectable()
export class UserEffects {
  constructor(
    private _actions$: Actions,
    private _store$: Store<IStore>,
    private _userService: UsersService,
  ) { }

  @Effect({ dispatch: true })
  userLogin$: Observable<Action> = this._actions$
    .ofType('USER_REDUCER_USER_LOGIN')
    .switchMap((action: Action) =>
      this._userService.checkPasswd(action.payload.username, action.payload.password)
        .map((user: any) => {
          return { type: 'USER_REDUCER_USER_LOGIN_SUCCESS', payload: user };
        })
        .catch((err) => {
          return Observable.of({ type: 'USER_REDUCER_USER_LOGIN_FAILED', payload: { error: err } });
        })
    );
}

所以,当发生错误时,我会抛出 USER_REDUCER_USER_LOGIN_FAILED 动作,所以 userLoginFailed

另一方面,我已经创建了这个与错误相关的操作:

export class ErrorReducer {
  private static reducerName = 'ERROR_REDUCER';

  public static reducer(user = initialErrorState(), {type, payload}: Action) {
    if (typeof ErrorReducer.mapActionsToMethod[type] === 'undefined') {
      return user;
    }

    return ErrorReducer.mapActionsToMethod[type](user, type, payload);
  }

    public static ERROR_APPEARS = `${ErrorReducer.reducerName}_APPEARS`;
    private static error(sourcesRdx, type, payload) {
        return Object.assign(<IError>{}, sourcesRdx, payload);
    }

  private static mapActionsToMethod = {
      [ErrorReducer.ERROR_APPEARS]: ErrorReducer.error
  };
}

但是我怎么能抛出 ERROR_REDUCER_APPEARS 动作呢?什么时候?在哪里?

我已尝试在用户效果内分派操作。不过,我不知道这是否是一种不好的做法:

  @Effect({ dispatch: true })
  userLogin$: Observable<Action> = this._actions$
    .ofType('USER_REDUCER_USER_LOGIN')
    .switchMap((action: Action) =>
      this._userService.checkPasswd(action.payload.username, action.payload.password)
        .map((user: any) => {
          return { type: 'USER_REDUCER_USER_LOGIN_SUCCESS', payload: user };
        })
        .catch((err: any) => {
          this._store$.dispatch({ type: 'ERROR_REDUCER_APPEARS', payload: { msg: err.message } });
          return Observable.of({ type: 'USER_REDUCER_USER_LOGIN_FAILED', payload: {} });
        })
    );
}

【问题讨论】:

    标签: ngrx


    【解决方案1】:

    简答

    答案其实很简单:

    让你的错误减少器减少USER_LOGIN_FAILED-action。

    reducer 负责它的应用状态切片,但不应仅限于减少可用操作的子集。 因此,一个reducer可以减少任何action,多个reducer可以减少同一个action。

    例如,如果 USER_LOGIN_FAILED-action 在您的用户效果中调度 您可以让 error-reducer 填充 store 的 error-slice,并且 user-reducer 将 store 的 user-slice 重置回初始状态(或对该操作有意义的任何其他内容)。 user-reducer 不一定要对USER_LOGIN_FAILED 做出反应。

    特定于您的代码

    首先,您的方法的主要问题是您在 reducer 中定义操作。 其次,您不需要ERROR_REDUCER_APPEARS-action 来实现我认为您正在努力实现的目标。

    效果:

    @Effect({ dispatch: true })
      userLogin$: Observable<Action> = this._actions$
        .ofType('USER_LOGIN')
        .switchMap((action: Action) =>
          this._userService.checkPasswd(action.payload.username, action.payload.password)
            .map((user: any) => {
              return { type: 'USER_LOGIN_SUCCESS', payload: user };
            })
            .catch((err) => {
              // you don't need to dispatch an additional action here
              return Observable.of({ type: 'USER_LOGIN_FAILED', payload: err });
            })
        );
    

    请注意,我重命名了您的操作。原因是 action 不应该特定于 reducer。

    不幸的是,这意味着您必须重写整个 reducer:

    用户缩减器:

    export class UserReducer {
        public static reducer(user = initialUserState(), {type, payload}: Action) {
            switch(type) {
                case 'USER_LOGIN_SUCCESS': {
                    return Object.assign(<IUser>{}, user, payload);
                }
                case 'USER_LOGIN_FAILED': {
                    // return initialstate or whatever makes sense.
                    // or remove the case-statement if nothing should change in the user-slice
                }
                default: {
                    return user;
                }
            }
        }
    }
    

    错误减少器:

    export class ErrorReducer {
        public static reducer(error = initialErrorState(), {type, payload}: Action) {
            switch(type) {
                case 'USER_LOGIN_FAILED': {
                    return Object.assign(<IError>{}, error, payload);
                }
                default: {
                    return error;
                }
            }
        }
    }
    

    我假设mapActionsToMethod 旨在使您的操作“类型安全”。 在我的示例中,您可以执行以下操作:

    user-actions.ts

    @Injectable()
    export class UserActions {
        static USER_LOGIN = "USER_LOGIN";
        static USER_LOGIN_SUCCESS = "USER_LOGIN_SUCCESS";
        static USER_LOGIN_FAILED = "USER_LOGIN_FAILED";
    }
    

    然后像这样替换字符串:

    case 'UserActions.USER_LOGIN_FAILED': {
        return Object.assign(<IError>{}, error, payload);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-29
      • 1970-01-01
      • 2019-08-09
      • 2021-05-24
      • 1970-01-01
      • 2020-06-13
      • 1970-01-01
      • 2019-03-17
      相关资源
      最近更新 更多