将 isValid 从子组件传递到父组件会延迟 1 个输入吗? (反应本机,福米克)

问题描述 投票:0回答:1

尝试使用子组件 (EditInput) 中 Formik TextInput 的数据动态设置父组件 (EditProfileScreen) 中提交按钮的样式,但 isValid 布尔值始终延迟,从而使正确的返回当前输入之后的值。

const EditInputs = ({userInfo, onInputChange}) => {
  const SignupFormSchema = Yup.object().shape({
    name: Yup.string()
      // .min(1, 'Name must be at least 1 characters')
      .max(20, 'Name has reached character limit'),
    username: Yup.string()
      .min(5, 'Username must be at least 5 characters')
      .max(20, 'Username has reached character limit')
      .matches(
        /^[A-Za-z0-9_]+$/,
        'Username can only contain letters, numbers, and underscores',
      ) // New regex
      .required('A username is required'),
    bio: Yup.string().max(200, 'Username has reached character limit'),
    email: Yup.string().email().required('An email is required'),
    number: Yup.string()
      //   .required('required')
      .matches(phoneRegExp, 'Phone number is not valid')
      .min(10, 'too short')
      .max(10, 'too long'),
    //   .nullable(),
  });

return (
    <View style={styles.wrapper}>
      <Formik
        initialValues={userInfo} // Use spread syntax for cleaner initialization
        validationSchema={SignupFormSchema}
        // validateOnBlur={true}
        validateOnChange={true}
        validateOnMount={true}
        onSubmit={values => {
          onInputChange(values, isValid); // Pass the whole 'values' object along with isValid
        }}>
        {({handleChange, handleBlur, handleSubmit, values, isValid}) => (
          <>
            <View>
              <View style={styles.inputContainer}>
                <Text
                  style={{
                    color: '#CCCCCC',
                    marginHorizontal: 18,
                    // marginVertical: 5,
                  }}>
                  Name
                </Text>
                <View
                  style={[
                    styles.inputField,
                    // {
                    //   borderColor:
                    //     1 < values.name.length ? '#52636F' : '#fa4437',
                    // },
                  ]}>
                  <TextInput
                    style={styles.input}
                    onChangeText={text => {
                      console.log(isValid);
                      handleChange('name')(text); // Update Formik state
                      onInputChange('name', text, isValid); // Pass isValid here
                    }}
                    onBlur={handleBlur('name')}
                    value={values.name}
                    placeholder="Name"
                    placeholderTextColor="#ACAFB0"
                    autoCapitalize="none"
                    autoCorrect={false}
                    textContentType="name"
                  />
                </View>

                {/* {isUsernameValid ? (
                <Image
                  style={[styles.icons, {tintColor: '#D39D34'}]}
                  source={require('../../assets/icons/excla-circle.png')}
                />
              ) : (
                <Image
                  style={[styles.icons, {tintColor: '#D39D34'}]}
                  source={require('../../assets/icons/excla-circle.png')}
                />
              )} */}
              </View>

              <View style={styles.inputContainer}>
                <View style={{flexDirection: 'row'}}>
                  <Text
                    style={{
                      color: '#CCCCCC',
                      marginLeft: 18,
                      // marginVertical: 5,
                    }}>
                    Username
                  </Text>
                  <Text
                    style={{
                      color: '#B93A21',
                      marginHorizontal: 3,
                      // marginVertical: 5,
                    }}>
                    *
                  </Text>
                </View>
                <View
                  style={[
                    styles.inputField,
                    {
                      borderColor:
                        // values.username === ''
                        //   ? '#52636F' // Default gray border if empty
                        //   :
                        values.username.length < 5
                          ? '#fa4437' // Red border for length violations
                          : !/^[A-Za-z0-9_]+$/.test(values.username)
                            ? '#fa4437' // Red border for invalid characters
                            : '#52636F', // Default gray border if valid
                    },
                  ]}>
                  <TextInput
                    style={styles.input}
                    onChangeText={text => {
                      // console.log(isValid);
                      handleChange('username')(text);
                      onInputChange('username', text, isValid); // Pass isValid here
                    }}
                    onBlur={handleBlur('username')}
                    value={values.username.trim()}
                    placeholder="Username"
                    placeholderTextColor="#ACAFB0"
                    autoCapitalize="none"
                    autoCorrect={false}
                    textContentType="username"
                  />
                </View>
                <Text
                  style={{
                    color: '#55646F',
                    marginHorizontal: 18,
                    fontSize: 12,
                    // marginVertical: 5,
                  }}>
                  You can only change your username once every 7 days.
                </Text>
              </View>

              <View style={styles.inputContainer}>
                <Text
                  style={{
                    color: '#CCCCCC',
                    marginHorizontal: 18,
                    // marginVertical: 5,
                  }}>
                  Bio
                </Text>
                <View
                  style={[
                    styles.inputField,
                    {
                      borderColor:
                        1 > values.bio.length || values.bio.length <= 200
                          ? '#52636F'
                          : '#fa4437',
                      // height: 100,
                    },
                  ]}>
                  <TextInput
                    style={[styles.input, {textAlignVertical: 'top'}]}
                    placeholderTextColor="#ACAFB0"
                    placeholder="Bio"
                    autoCapitalize="none"
                    autoCorrect={true}
                    textContentType="none"
                    onChangeText={text => {
                      handleChange('bio')(text);
                      onInputChange('bio', text, isValid); // Pass isValid here
                    }}
                    onBlur={handleBlur('bio')}
                    value={values.bio}
                    multiline={true}
                    numberOfLines={5}
                    maxLength={200}
                  />
                </View>
                <Text
                  style={{
                    color: '#55646F',
                    marginHorizontal: 18,
                    fontSize: 12,
                    // marginVertical: 5,
                  }}>
                  Brief description of your profile. URLs are hyperlinked.
                </Text>
              </View>

              <View style={styles.inputContainer}>
                <View style={{flexDirection: 'row'}}>
                  <Text
                    style={{
                      color: '#CCCCCC',
                      marginLeft: 18,
                      // marginVertical: 5,
                    }}>
                    Email Address
                  </Text>
                  <Text
                    style={{
                      color: '#B93A21',
                      marginHorizontal: 3,
                      // marginVertical: 5,
                    }}>
                    *
                  </Text>
                </View>
                <View
                  style={[
                    styles.inputField,
                    {
                      borderColor:
                        values.email.length < 1 || validate(values.email)
                          ? '#52636F'
                          : '#fa4437',
                    },
                  ]}>
                  <TextInput
                    style={styles.input}
                    placeholderTextColor="#ACAFB0"
                    placeholder="Email"
                    autoCapitalize="none"
                    keyboardType="email-address"
                    textContentType="emailAddress"
                    autoFocus={false}
                    onChangeText={text => {
                      handleChange('email')(text);
                      onInputChange('email', text, isValid); // Pass isValid here
                    }}
                    onBlur={handleBlur('email')}
                    value={values.email}
                  />
                  <TouchableOpacity
                    style={{
                      alignSelf: 'center',
                      // justifyContent: 'center',
                      backgroundColor: '#5034FF',
                      paddingHorizontal: 15,
                      paddingVertical: 7,
                      borderRadius: 20,
                    }}>
                    <Text style={{color: 'white'}}>Verify</Text>
                  </TouchableOpacity>
                </View>
              </View>

              <View style={styles.inputContainer}>
                <Text
                  style={{
                    color: '#CCCCCC',
                    marginHorizontal: 18,
                    // marginVertical: 5,
                  }}>
                  Phone Number
                </Text>
                <View
                  style={[
                    styles.inputField,
                    {
                      borderColor:
                        values.number === ''
                          ? '#52636F' // Default gray border if empty
                          : values.number.length > 11 ||
                              !phoneRegExp.test(values.number)
                            ? '#fa4437' // Red border for invalid input
                            : '#52636F', // Default grey border for valid input
                    },
                  ]}>
                  <TextInput
                    style={styles.input}
                    placeholderTextColor="#ACAFB0"
                    placeholder="Phone Number"
                    autoCapitalize="none"
                    autoCorrect={false}
                    keyboardType="phone-pad"
                    textContentType="telephoneNumber"
                    onChangeText={text => {
                      handleChange('number')(text);
                      onInputChange('number', text, isValid); // Pass isValid here
                    }}
                    onBlur={handleBlur('number')}
                    value={values.number}
                  />
                  <TouchableOpacity
                    style={{
                      alignSelf: 'center',
                      backgroundColor: '#5034FF',
                      paddingHorizontal: 15,
                      paddingVertical: 7,
                      borderRadius: 20,
                    }}>
                    <Text style={{color: 'white'}}>Verify</Text>
                  </TouchableOpacity>
                </View>
                <ErrorMessage
                  name="number"
                  component={Text}
                  style={styles.errorText}
                />
              </View>
            </View>
          </>
        )}
      </Formik>
    </View>
  );
};
const EditProfileScreen = ({route, navigation}) => {
  const [formIsValid, setFormIsValid] = useState(true); // Assume valid initially
...
const handleInputChange = (name, value, isValid) => {
    setInputValues(prevValues => ({...prevValues, [name]: value}));
    // console.log(isValid);
    setFormIsValid(isValid); // Update form validity from EditInputs
    // setHasChanges(true);
  };

const SaveButton = () => (
    <View style={{position: 'absolute', bottom: 20, right: 30}}>
      {hasChanges && (
        <Pressable
          onPress={handleSavePress}
          style={({pressed}) => [
            styles.saveButton,
            {
              backgroundColor:
                !formIsValid || isSubmitting // Check form validity AND submission state
                  ? '#838383' // Greyed out if invalid or submitting
                  : pressed
                    ? '#772414'
                    : '#B93A21',
              opacity: pressed ? 0.5 : 1,
            },
          ]}
          disabled={!formIsValid || isSubmitting} // Disable if invalid or submitting
        >
          {isSubmitting ? (
            <ActivityIndicator color="white" />
          ) : (
            <Image
              style={styles.icon}
              source={require('../assets/icons/floppy-disk.png')}
            />
          )}
        </Pressable>
      )}
    </View>
  );

return (
    <SafeAreaView style={styles.container}>
      <>
        <ScrollView>
          <EditImages userInfo={userInfo} onImageChange={handleImageChange} />
          <EditInputs
            userInfo={inputValues}
            onInputChange={handleInputChange}
          />
        </ScrollView>
        <EditHeader navigation={navigation} userInfo={userInfo} />
        <SaveButton />
      </>
    </SafeAreaView>
  );
};

例如-

用户名输入(只能是数字、字母和下划线。必须有 5 - 20 个字符):

  1. ch_ezey(以用户名开头)
  2. ch_ezey1(+'1')
  3. ch_ezey1@(+“@”)
  4. ch_ezey1(-'@')
  5. ch_ezey1@(+“@”)
  6. ch_ezey (- '1@')

预期:

 LOG  true
 LOG  true
 LOG  false
 LOG  true
 LOG  false
 LOG  true

结果:

 LOG  true
 LOG  true
 LOG  true
 LOG  false
 LOG  true
 LOG  false
react-native input frontend formik
1个回答
0
投票

可以通过在 JavaScript 表达式中使用 setState 将 Formik 验证从 ChildComponent 传递到 ParentComponent 。我把事情复杂化了。在我的 Formik 组件中添加了这个:

{onValidationChange(isValid)}

const [isFormValid, setIsFormValid] = useState(false);

<EditInputs ... onValidationChange={setIsFormValid} />

这样就没有延迟了。但是,如果有人向我解释为什么其他方法有延迟,我将不胜感激。

© www.soinside.com 2019 - 2024. All rights reserved.