使用 redux observable 显示警告框

Show alert box using redux observable

我在我的 React Native 应用程序中使用 redux observable,如果凭据无效,我想在我的登录屏幕上显示一个 React Native 警报对话框。我可以在我的史诗中触发警报但在史诗中我只能 return 一个可观察的,那么如何使用 redux 可观察的来实现这个?

验证码:

export const signInFailure = (payload) => {
  return {
    type: SIGN_IN_FAILURE,
    payload
  }
};


const signInSuccessActions = (payload) => {
return Observable.concat(
    Observable.of({type: SIGN_IN_SUCCESS, payload}),
    Observable.of({type: 'Navigation/NAVIGATE', routeName:          'MainTabView'})
);
 };


export const signInRequestEpic = action$ =>
action$.ofType(SIGN_IN_REQUEST)
    .mergeMap(action => AuthService.login(action.email,  action.password)
        .flatMap(payload => payload.status === 200 ?  signInSuccessActions(payload) : signInFailure(payload))
        .catch(error => Observable.of({
            type: SIGN_IN_FAILURE,
            error
        }))
    );

在 React Native 中使用警报 api 只是 1 行

import {Alert} from "react-native";

 Alert.alert(
        'Invalid',
        'Email or password incorrect',
    )

更好的方法是在减速器中为 SIGN_IN_FAILURE 设置一个状态以及原因。在登录屏幕中使用这些并在 componentWillReceiveProps 中显示警报或在 render 方法中显示自定义模式错误消息 像这样

class LoginScreen{
  componentWillMount(){
    this.componentWillReceiveProps(this.props);
  }
  componentWillReceiveProps(nextProps){
    const { loginError } = nextProps.loginState;
    if(loginError){
      Alert.alert('Invalid','Email or password incorrect')
    }
  }
  render() {
    const { loginError } = this.props.loginState
    <View>
      <Modal visible={loginError}>
      </Modal>
    </View>
  }
}
const mapStateToProps = (state) => {
  return {
    loginState: state.login,
  };
};

LoginScreen = connect(mapStateToProps)(LoginScreen);
export default LoginScreen;

确保在警报对话框关闭后重置 loginError redux 状态

旁注:大多数问题实际上只是普通的 RxJS questions in disguise,并不特定于 redux-observable;这几乎将所有内容都推迟到常规 RxJS。如果您能够将问题概括为普通的 RxJS,而无需 redux-observable 术语,找到答案通常会更容易,因为有大量的 RxJS 资源以及 Whosebug、Gitter 等用户可以提供帮助。


有几种方法可以做到。

在您现有的 Epic 中执行此操作

您可以使用 .do() operator 产生不以任何方式影响操作流的副作用——比如只显示一个警告框而不进行任何确认。

export const signInRequestEpic = action$ =>
  action$.ofType(SIGN_IN_REQUEST)
    .mergeMap(action =>
      AuthService.login(action.email, action.password)
        .flatMap(payload => payload.status === 200
          ? signInSuccessActions(payload)
          : signInFailure(payload)
        )
        .do({
          error: ({ payload }) =>
            Alert.alert('Invalid', `Sign in failed: ${payload.message}`)
        })
        .catch(error => Observable.of({
          type: SIGN_IN_FAILURE,
          error
        }))
    );

您也可以在 return SIGN_IN_FAILURE 的流之前在 .catch() 中执行此操作,但我个人喜欢将副作用分开,使它们更加突出。但这是:

.catch(error => {
  Alert.alert('Invalid', `Sign in failed: ${error.message}`);

  return Observable.of({
    type: SIGN_IN_FAILURE,
    error
  });
})

史诗

中完成

如果您希望从 signInRequestEpic 中抽象出这种副作用,您可以创建另一个只监听失败的史诗,并使用 .do() 显示警报,然后使用 .ignoreElements() 运算符忽略匹配的动作,因为这个史诗不需要发出任何东西。

export const signInFailureEpic = action$ =>
  action$.ofType(SIGN_IN_FAILURE)
    .do(({ payload }) =>
      Alert.alert('Invalid', `Sign in failed: ${payload.message}`)
    )
    .ignoreElements();

你应该使用哪一个?这取决于。如果您希望在 之前 更新您的 redux 商店,则显示警报,那么您肯定会想要使用单独的 Epic。对于第二个史诗,SIGN_IN_FAILURE 操作将在 signInFailureEpic 收到之前已经到达您的减速器,因此它们将被更新。如果您在 signInRequestEpic 中执行此操作,则操作还不会到达减速器。

商店更新并出现在同一个史诗中是可能的,但它开始变得毛茸茸,所以我不打算展示如何 ;)

没用过React Native,但你能做这样的事吗?然后在 AuthService.login()?

的 catch 中调度这个动作
export const toggleAlert = action$ =>
    action$.ofType(OPEN_ERROR_TOAST)
    .map(action => Alert.alert('Invalid',action.payload))
    .switchMap(alert => {
      alert.open();
      return action$
        .ofType('CLOSE_ERROR_TOAST')
        .do(_ => alert.close())
    })