首页 > 解决方案 > useValidation 挂钩未按预期工作

问题描述

我有一个注册屏幕,我已经为它构建了两个 costom 挂钩。

  1. useSignup 在其中定义了我的注册方法及其本地
  2. 我在其中定义了验证方法的 util 钩子。

但我无法按预期使用验证方法。这是注册屏幕

import React, {useState} from 'react';
import {
  View,
  Text,
  StatusBar,
  Keyboard,
  TouchableOpacity,
  ScrollView,
} from 'react-native';
import Icon from 'react-native-vector-icons/AntDesign';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
import Input from '../../../components/input';
import Btn from '../../../components/button';
import CheckBox from '../../../components/checkbox';
import PressableText from '../../../components/pressable';
import {styles} from './style';
import useSignup from './customHooks/useSignup';
import useValidation from './customHooks/utils';

const Signup = ({navigation}) => {
  const [
    id,
    setId,
    name,
    setName,
    email,
    setEmail,
    pass,
    setPass,
    confirmPass,
    setConfirmPass,
    validated,
    setValidated,
  ] = useSignup();
  const [validation] = useValidation();

  
  return (
    <View style={styles.container}>
      <StatusBar barStyle="dark-content" />
      <TouchableOpacity activeOpacity={1} onPress={() => Keyboard.dismiss()}>
        <ScrollView contentContainerStyle={styles.ScrollView}>
          <View style={styles.backIconView}>
            <Icon
              name="arrowleft"
              size={40}
              color={'#807D89'}
              onPress={() => navigation.goBack()}
            />
          </View>
          <View style={styles.textView}>
            <Text style={styles.heading}>Create Account</Text>
            <Text style={styles.para}>Please fill input below to continue</Text>
          </View>
          <KeyboardAwareScrollView
            resetScrollToCoords={{x: 0, y: 0}}
            contentContainerStyle={styles.loginForm}>
            <Input
              text="ID"
              placeholder="Enter Your ID"
              keyboardType="number-pad"
              icon="key"
              secureTextEntry={false}
              value={id}
              onChangeText={(e) => setId(e)}
            />
            <Input
              text="Full Name"
              placeholder="Enter Name"
              keyboardType="default"
              icon="user"
              secureTextEntry={false}
              value={name}
              onChangeText={(e) => {
                setName(e);
              }}
            />
            <Input
              text="Email"
              placeholder="Enter Email"
              keyboardType="email-address"
              icon="mail"
              secureTextEntry={false}
              value={email}
              onChangeText={(e) => setEmail(e)}
            />
            <Input
              text="Password"
              placeholder="Enter Password"
              keyboardType="default"
              icon="lock"
              secureTextEntry={true}
              value={pass}
              onChangeText={(e) => setPass(e)}
            />
            <Input
              text="Confirm Password"
              placeholder="Enter Password"
              keyboardType="default"
              icon="lock"
              secureTextEntry={true}
              value={confirmPass}
              onChangeText={(e) => setConfirmPass(e)}
            />
            <View style={styles.checkboxView}>
              <CheckBox />
              <View style={{flexDirection: 'row'}}>
                <Text style={{...styles.signUpViewText, fontSize: 20}}>
                  I accept all{' '}
                </Text>
                <PressableText
                  text={'Terms and Conditions'}
                  fontSize={18}
                  action={() => alert('Terms')}
                />
              </View>
            </View>
            <Btn
              text="Sign Up"
              action={() => {
                validation();
                if (validated) {
                  useSignup();
                  navigation.navigate('Home');
                }
              }}
            />
          </KeyboardAwareScrollView>
          <View style={styles.signUpView}>
            <Text style={styles.signUpViewText}>Already have an account? </Text>
            <PressableText
              text="LogIn"
              fontSize={18}
              action={() => navigation.navigate('Login')}
            />
          </View>
        </ScrollView>
      </TouchableOpacity>
    </View>
  );
};
export default Signup;

这是 useSignup 钩子:

import React, {useState} from 'react';
import auth from '@react-native-firebase/auth';

export default useSignup = () => {
  //   auth()
  //     .createUserWithEmailAndPassword(email, pass)
  //     .then(() => {
  //       console.log('User account created & signed in!');
  //       alert(`signed in with ${email}`);
  //     })
  //     .catch((error) => {
  //       if (error.code === 'auth/email-already-in-use') {
  //         console.log('That email address is already in use!');
  //       }

  //       if (error.code === 'auth/invalid-email') {
  //         console.log('That email address is invalid!');
  //       }

  //       console.error(error);
  //     });
  //   console.log(email, 'email');
  //   console.log(pass, 'pass');
  const [id, setId] = useState('');
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [pass, setPass] = useState('');
  const [confirmPass, setConfirmPass] = useState('');
  const [validated, setValidated] = useState(false);
  console.log(id, 'in signup');

  return [
    id,
    setId,
    name,
    setName,
    email,
    setEmail,
    pass,
    setPass,
    confirmPass,
    setConfirmPass,
    validated,
    setValidated,
  ];
};

这是 useValidation 钩子:

import useSignup from './useSignup';

export default useValidation = () => {
  const [id, name, email, pass, confirmPass, setValidated] = useSignup();
  console.log(id, 'in utils');
  const validation = () => {
    id == ''
      ? alert('Enter ID')
      : name == '' || email == ''
      ? alert('User not Found')
      : pass == '' || confirmPass == ''
      ? alert('enter Password')
      : pass != confirmPass
      ? alert('Pass does not match')
      : setValidated(true);
  };
  return [validation];
};

我究竟做错了什么?

标签: reactjsreact-nativereact-hooks

解决方案


不完全确定你想要完成什么。对我来说,自定义钩子应该是可重用的并且可以描述它们的响应。我想 useSignup 很好,但对我来说 useValidation 听起来不应该绑定到 useSignup 并且可能以其他形式使用,以及不同的元素和验证规则。

下面的代码可以在https://codesandbox.io/s/musing-vaughan-srw66找到和测试

如果您想为表单使用自定义钩子,一个想法是使整个表单成为一个钩子。在代码中,我没有使用 useSignup 或 useValidateor,而是使用处理表单元素和事件逻辑的 useForm。默认值可以作为可选的第三个参数添加到 useForm 或在带有 values.email || 的表单元素的 value 属性中添加 'test@testson.com'。我还外包了 validate 函数,以便 useForm 可以与任何表单和 validate 方法一起使用,以使其可重用。

useForm.js
const useForm = (validate, onSubmit, initalValues) => {
  const [values, setValues] = useState(initalValues ? initalValues : {});
  const [errors, setErrors] = useState([]);
  const [isSubmitting, setIsSubmitting] = useState(false);

  useEffect(() => {
    if (Object.keys(errors).length === 0 && isSubmitting) onSubmit();
    setIsSubmitting(false);
  }, [errors]);

  const handleSubmit = (event) => {
    event.preventDefault();
    setErrors(validate(values));
    setIsSubmitting(true);
  };

  const setValue = (name, value) => {
    setValues((values) => ({
      ...values,
      [name]: value
    }));
  };

  return {
    setValue,
    handleSubmit,
    values,
    errors
  };
};
App.js
const formValidatior = (values) => {
  const errors = [];
  if (!values || !values.email) errors.push("Email must be specified");
  const emailRegex = /^(([^<>()[\]\\.,;:\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,}))$/;
  if (!emailRegex.test(String(values.email).toLowerCase()))
    errors.push("Email not valid");
  //Other validation of values
  return errors;
};

export default function Form() {
  const { values, errors, setValue, handleSubmit } = useForm(
    formValidatior,
    handleValidationSuccessOnSubmit
    //{ email: "test" } //possibility to add initial values or nonform values
  );

  function handleValidationSuccessOnSubmit() {
    console.log("PASSED VALIDATION");
  }

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <label>Email</label>
        <input
          type="text"
          name="email"
          placeholder="Your email..."
          onChange={(event) => setValue(event.target.name, event.target.value)}
          value={values.email || ""} // "" becomes default value
        />
        <input type="submit" value="Submit" />
        {errors ? errors.map((error) => <p>{error}</p>) : null}
      </form>
    </div>
  );
}

来自https://upmostly.com/tutorials/form-validation-using-custom-react-hooks的想法


推荐阅读