内联反应本机显示验证错误

时间:2018-10-10 05:12:42

标签: javascript react-native

我是React Native的完全菜鸟,我只是想摆脱它。

我有一个简单的登录屏幕,该屏幕是使用“容器/演示文稿”组件概念开发的。我的演示文稿组件仅具有渲染功能,可渲染三个TextInput和一个Button。

我不想在Toasts上显示错误,而是想在TextInput本身下面显示错误。因此,我所做的是在TextInput下面添加了Text元素。像下面这样。

<TextInput placeholder="Email"></TextInput>
<Text ref="emailErrors"></Text>

默认情况下,带有ref emailErrors的文本被隐藏。但是,当焦点从Email TextInput转移并且如果email由于某些原因无效时,我想生成一个简单的错误,并将其设置为带有ref emailErrors的Text元素的文本。

现在,我了解到我将不得不在容器组件中编写逻辑并将其作为prop传递给表示组件。但是我无法理解的是如何触发错误文本的设置并显示Text元素。

更新:

我的演示组件:

class LoginForm extends Component {

  constructor(props) {
    super(props);
  }

  render() {
    return (

      <KeyboardAvoidingView
        style={styles.loginFormContainer}>

        <ScrollView
          scrollEnabled={true}
          enableOnAndroid={true}
          enableAutomaticScroll={true}
          keyboardDismissMode="on-drag"
          keyboardShouldPersistTaps="always"
          resetScrollToCoords={{ x: 0, y: 0 }}
          showsVerticalScrollIndicator={false}
          showsHorizontalScrollIndicator={false}>

          <View style={styles.loginForm}>
            <Image
              source={require("../../../assets/images/logos/logo.png")}
              style={styles.logoImage}></Image>

            <View style={styles.textInputWithIcon}>
              <Image
                style={styles.textInputIcon}
                source={require("../../../assets/images/icons/email.png")}
              ></Image>
              <View style={styles.textField}>
                <TextInput name="email"
                  ref="email"
                  placeholder="Email"
                  blurOnSubmit={false}
                  returnKeyType={"next"}
                  underlineColorAndroid={COLORS.red}
                  onSubmitEditing={() => this.refs.password.focus()}
                  style={[GLOBALSTYLES.textInput, styles.textInput]}
                  onChangeText={(text) => this.props.onEmailTextChanged(text)}
                >
                </TextInput>
                <Text
                  ref="email">
                </Text>
              </View>
            </View>

            <View style={styles.textInputWithIcon}>
              <Image
                style={styles.textInputIcon}
                source={require("../../../assets/images/icons/locked.png")}
              ></Image>
              <View style={styles.textField}>
                <TextInput name="password"
                  ref="password"
                  blurOnSubmit={false}
                  placeholder="Password"
                  secureTextEntry={true}
                  returnKeyType={"next"}
                  style={styles.textInput}
                  underlineColorAndroid={COLORS.red}
                  onSubmitEditing={() => Keyboard.dismiss()}
                  style={[GLOBALSTYLES.textInput, styles.textInput]}
                  onChangeText={(text) => this.props.onPasswordTextChanged(text)}
                  onBlur={() => this.props.onPasswordTextBlurred()}
                ></TextInput>
                <Text
                  ref="password">
                </Text>
              </View>
            </View>

            <TouchableOpacity
              activeOpacity={0.5}
              onPress={() => { this.props.onLoginPressed() }}
              style={styles.loginButton}
              underlayColor={COLORS.white}>
              <Text style={styles.loginButtonText}>Login</Text>
            </TouchableOpacity>
          </View>

        </ScrollView>

      </KeyboardAvoidingView>

    )

  };

};


export default LoginForm;

我的容器组件:

class Login extends Component {

  static navigationOptions = ({ navigation }) => ({
    "title": "Login"
  });

  constructor(props) {

    super(props);
    this.state = {}

  }


  // onLoginPressed will trigger the authentication workflow with the remote server.

  onLoginPressed() {

    const { isUserLoggedIn, email, password } = this.state;

    if (this.state.isEmailValid && this.state.isPasswordValid) {

      axios.post(CONFIGURATION.LOGIN_URL, {
        username: email,
        password: password
      }).then(response => {

        const navigationParams = {
          baseUrl: response.data.url,
          token: response.data.token,
          username: email
        }

        this.props.dispatch(loginSuccess(navigationParams));

        // Adding retrieved values to AsyncStorage
        AsyncStorage.multiSet(
          [
            [IS_USER_LOGGED_IN, "YES"],
            [USER, email],
            [TOKEN, response.data.token],
            [BASE_URL, response.data.url]
          ],
          () => {
            this.props.navigation.navigate("WebApp", navigationParams);
          });

      }).catch(error => {

        console.error(error);
        ToastAndroid.show("Authentication Failed", ToastAndroid.SHORT);

      });

    }

  }

  // Updating the state key email
  onEmailTextChanged(text) {
    this.setState({ "email": text });
  }

  // Updating the state key password
  onPasswordTextChanged(text) {
    this.setState({ "password": text });
  }

  onEmailTextBlurred() {

    var text = this.state.email;
    console.warn(text);

    if (text == undefined || text.trim().length == 0) {
      this.setState({ "isEmailValid": false });
      this.setState({ "emailErrorMessage": "Email cannot be empty" });
    }
    else {
      var regex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

      var isEmailValid = regex.test(text);
      if (!isEmailValid) {
        this.setState({ "isEmailValid": false });
        this.setState({ "emailErrorMessage": "Email is incorrect." });
      }
      else {
        this.setState({ "isEmailValid": true });
      }
    }

  }

  onPasswordTextBlurred() {

    var text = this.state.password;

    if (text == undefined || text.trim().length == 0) {
      this.setState({ "isPasswordValid": false });
      this.setState({ "passwordErrorMessage": "Password cannot be empty" });
    }
    else {
      this.setState({ "isPasswordValid": true });
    }

  }

  // rendering the LoginForm (presentational component) corresponding to this container component
  render() {
    return (
      <LoginForm
        onLoginPressed={() => this.onLoginPressed()}
        onEmailTextChanged={(text) => this.onEmailTextChanged(text)}
        onPasswordTextChanged={(text) => this.onPasswordTextChanged(text)}
        onEmailTextBlurred={() => this.onEmailTextBlurred()}
        onPasswordTextBlurred={() => this.onPasswordTextBlurred()}
      />
    )
  }

}

const mapStateToProps = (state) => {

  return state;

}


const mapDispatchToProps = (dispatch) => {

  const boundActionCreators = bindActionCreators(loginSuccess, dispatch);
  return { ...boundActionCreators, dispatch };

}


export default connect(mapStateToProps, mapDispatchToProps)(Login);

1 个答案:

答案 0 :(得分:1)

您可以在组件状态下使用标志,通过检查标志的状态来检查是否给出了无效输入。

例如:

emailValidationRegex(v){
    // use regex to check if email is valid and return  true if email is valid, false if email is invalid
}

<TextInput 
    placeholder="Email" 
    onChange={(v)=>{this.setState({
        email: v,
        isEmailInvalid: !emailValidationRegex(v)
    })}} >
</TextInput>
{this.state.isEmailInvalid && <Text>Sorry! Invalid Email</Text>} 

说明:
isEmailInvalid保留给定电子邮件地址的状态(无论该地址是否有效)。根据其状态,有条件地显示以下错误。

更新:

在容器组件的onEmailTextChanged方法中,如果电子邮件有效或无效,则将另一个状态更新为保留状态:

onEmailTextChanged(text) {
    this.setState({ "email": text, isEmailInvalid: !emailValidationRegex(text) });
  }

然后在发送给演示组件的道具中传递this.state.isEmailInvalid。然后在演示组件中有条件地显示错误。

容器组件的渲染方法:

render() {
    return (
      <LoginForm
        onLoginPressed={() => this.onLoginPressed()}
        onEmailTextChanged={(text) => this.onEmailTextChanged(text)}
        isEmailInvalid={this.state.isEmailInvalid}
        onPasswordTextChanged={(text) => this.onPasswordTextChanged(text)}
        onEmailTextBlurred={() => this.onEmailTextBlurred()}
        onPasswordTextBlurred={() => this.onPasswordTextBlurred()}
      />
    )

现在您可以在演示组件中使用this.props.isEmailInvalid