我在构建注册页面时遇到了一个问题。
具体来说,我打算使表单验证检查功能,当我单击每个输入。
但是,它可以将所有输入一起工作。
谁能让我知道在我的代码更正哪里?
概要:
-
要使验证检查功能。它对每个输入分别工作。
-
做到了,然而,当我点击任何一个输入时,那么所有输入的错误都被激活了。
-
我找不到它的错误,猜测只使用一个状态?const [focused, setFocused] = useState(false);">
-
附加信息,我能够找到焦点功能的工作,然而,所有的输入激活在一起…考虑是否应该为每个值使用单独的状态?同时,还可以有很多干净、整洁的方式……!
欣赏!
// Signup.css
span {
font-size: 12px;
padding: 3px;
color: red;
display: none;
}
input:invalid[focused="true"] {
border: 1px solid red;
}
input:invalid[focused="true"] ~ span {
display: block;
}
//Signup.js
function(props) {
const navigate = useNavigate();
const [id, setId] = useState("");
const [password, setPassword] = useState("");
const [passwordConfirm, setPasswordConfirm] = useState("");
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [email, setEmail] = useState("");
const [focused, setFocused] = useState(false);
const handleFocus = (e) => {
setFocused(true);
};
return (
<>
<div className='full-box'>
<div id='signup-middle-box' className='middle-box'>
<h2>SignUp</h2>
<form onSubmit={SignUpUser}>
<div id='signup-small-box' className='small-box'>
<div className='signup-box'>
<div className='signup-forms'>
<h6>ID</h6>
<div id='forms-with-button'>
<div className='forms-with-btn'>
<input
placeholder='ID'
value={id}
onChange={(e) => setId(e.target.value)}
type='text'
name='id'
id='Id'
onBlur={handleFocus}
focused={focused.toString()}
required
/>
<span>
<img src={redWarning} alt={redWarning} />
Please fill ID
</span>
</div>
<div>
<button onSubmit={CheckUser}>CheckUser</button>
</div>
</div>
</div>
<div className='signup-forms'>
<div className='pw-box'>
<h6>Password</h6>
<p>
<img src={warning} alt={warning} /> Password should be 8-20 characters and include at least 1 letter, 1 number and 1 special character!
</p>
</div>
<div className='forms-without-btn'>
<input
placeholder='Please type password'
value={password}
onChange={(e) => setPassword(e.target.value)}
type='password'
name='password'
id='password'
autoComplete='off'
pattern={`^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{8,20}$`}
onBlur={handleFocus}
focused={focused.toString()}
required
></input>
<input
placeholder='Repeat the password'
value={passwordConfirm}
onChange={(e) => setPasswordConfirm(e.target.value)}
type='password'
name='passwordConfirm'
id='pwRepeat'
autoComplete='off'
onBlur={handleFocus}
focused={focused.toString()}
pattern={`^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{8,20}$`}
onFocus={() =>
password === "passwordConfirm" && setFocused(true)
}
required
></input>
<span>
<img src={redWarning} alt={redWarning} />
Passwords don't match !
</span>
</div>
</div>
<div className='signup-forms'>
<h6>Name</h6>
<div className='forms-without-btn'>
<input
placeholder='Type your name'
value={name}
onChange={(e) => setName(e.target.value)}
type='text'
name='name'
id='Name'
autoComplete='off'
pattern={`^[가-힣]{2,4}$`}
focused={focused.toString()}
onBlur={handleFocus}
required
></input>
<span>
<img src={redWarning} alt={redWarning} />
Check your name
</span>
</div>
</div>
<div className='signup-forms'>
<h6>Phone</h6>
{isPhonecertiOn === true ? (
<PhoneCertificate
isPhonecertiOn={isPhonecertiOn}
setPhoneCertiOn={setPhoneCertiOn}
/>
) : (
<div id='forms-with-button'>
<div className='forms-with-btn'>
<input
// style={style}
placeholder='Enter your phone'
value={phone}
onChange={(e) => setPhone(e.target.value)}
type='text'
name='phone'
id='Phone'
autoComplete='off'
pattern={`^(010|011|016|017|018|019)[0-9]{3,4}[0-9]{4}$`}
focused={focused.toString()}
required
></input>
<span>
<img src={redWarning} alt={redWarning} />
Phone has 11 digits
</span>
</div>
<div>
<button
id='phone-certification'
onClick={() => setPhoneCertiOn(true)}
>
<img src={phone_certi} alt={phone_certi} />
Phone Certification
</button>
</div>
</div>
)}
</div>
<span>
<img src={redWarning} alt={redWarning} />
Phone has 11 digits.
</span>
<div className='signup-forms'>
<h6>Email</h6>
{isEmailcertiOn === true ? (
<EmailCertificate
isEmailcertiOn={isEmailcertiOn}
setEmailcertiOn={setEmailcertiOn}
/>
) : (
<div id='forms-with-button'>
<div className='forms-with-btn'>
<input
// style={style}
placeholder='Type your email'
value={email}
onChange={(e) => setEmail(e.target.value)}
type='text'
name='email'
id='email'
autoComplete='off'
onBlur={handleFocus}
focused={focused.toString()}
required
></input>
<span>
<img src={redWarning} alt={redWarning} />
Please enter exact email form
</span>
</div>
<div>
<button
id='email-certification'
onClick={() => setEmailcertiOn(true)}
>
<img src={email_certi} alt={email_certi} />
Email certification
</button>
</div>
</div>
)}
</div>
<div className='signup-forms'>
<button id='signup-btn'>Submit</button>
<button
id='signup-cancle-btn'
onClick={() => {
props.setFormsOn(false);
}}
>
Cancle
</button>
</div>
</div>
</div>
</form>
</div>
</div>
}
我认为解决这个问题最全面的方法如下:
为每个表单输入设置一个isValid状态
让验证检查函数为所有输入设置isValid状态。
我有一个表单组件的例子,你可以使用它作为参考,尽管它是在typescript中实现的,所以语法会略有不同。
const LoginForm = ({email, setEmail, password, setPassword, onLogin, loading}: LoginFormPropTypes) => {
const [isVisiblePassword, setIsVisiblePassword] = useState(false);
const [validEmail, setValidEmail] = useState(true);
const [emailHelper, setEmailHelper] = useState<string | null>(null);
const [validPassword, setValidPassword] = useState(true);
const [passwordHelper, setPasswordHelper] = useState<string | null>(null);
const {colors} = useTheme();
// Setting form validation states and helperText using validator
const validateForm = (input: 'email' | 'password' | 'all') => {
let allowSubmit = true;
if(input === 'email' || input === 'all') {
if(!validator.isLength(email, {min: 1})) {
setValidEmail(false);
setEmailHelper('Email field cannot be empty');
allowSubmit = false;
} else if(!validator.isEmail(email) || !validator.isLength(email, {max: 320})){
setValidEmail(false);
setEmailHelper('The Email provided is invalid');
allowSubmit = false;
} else {
setValidEmail(true);
}
}
if(input === 'password' || input === 'all') {
if(!validator.isLength(password, {min: 1})) {
setValidPassword(false);
setPasswordHelper('Password field cannot be empty');
allowSubmit = false;
} else if(!validator.isLength(password, {max: 200})) {
setValidPassword(false);
setPasswordHelper('Password exceeds maximum length of 200')
allowSubmit = false;
} else {
setValidPassword(true);
}
}
return allowSubmit;
}
// Checking if form is valid before submitting
const onSubmitHandler = () => {
if(validateForm('all')){
onLogin?.();
}
}
return (
<CardWrapper>
<Card.Content>
<TextInput
label="Email"
mode="outlined"
style={styles.textInput}
onChangeText={setEmail}
value={email}
dense
error={!validEmail}
onBlur={() => {validateForm('email')}}
/>
<HelperText
type="error"
visible={!validEmail}
style={{display: !validEmail ? undefined : 'none'}}
>
{emailHelper}
</HelperText>
<TextInput
label="Password"
mode="outlined"
style={{...styles.textInput, ...styles.marginTop}}
onChangeText={setPassword}
value={password}
dense
secureTextEntry={!isVisiblePassword}
onBlur={() => {validateForm('password')}}
right={
<TextInput.Icon
color={(isFocused) =>
validPassword
? (isFocused ? colors.primary : 'black')
: colors.error
}
forceTextInputFocus={false}
onPress={() => setIsVisiblePassword(!isVisiblePassword)}
name={isVisiblePassword ? "eye-off" : "eye"}
/>
}
error={!validPassword}
/>
<HelperText
type="error"
visible={!validPassword}
style={{display: !validPassword ? undefined : 'none'}}
>
{passwordHelper}
</HelperText>
<Button
style={{marginTop: 15}}
mode="contained"
onPress={onSubmitHandler}
loading={loading}
>
Login
</Button>
</Card.Content>
</CardWrapper>
);
};
const LoginForm = ({email, setEmail, password, setPassword, onLogin, loading}: LoginFormPropTypes) => {
const [isVisiblePassword, setIsVisiblePassword] = useState(false);
const [validEmail, setValidEmail] = useState(true);
const [emailHelper, setEmailHelper] = useState<string | null>(null);
const [validPassword, setValidPassword] = useState(true);
const [passwordHelper, setPasswordHelper] = useState<string | null>(null);
const {colors} = useTheme();
// Setting form validation states and helperText using validator
const validateForm = (input: 'email' | 'password' | 'all') => {
let allowSubmit = true;
if(input === 'email' || input === 'all') {
if(!validator.isLength(email, {min: 1})) {
setValidEmail(false);
setEmailHelper('Email field cannot be empty');
allowSubmit = false;
} else if(!validator.isEmail(email) || !validator.isLength(email, {max: 320})){
setValidEmail(false);
setEmailHelper('The Email provided is invalid');
allowSubmit = false;
} else {
setValidEmail(true);
}
}
if(input === 'password' || input === 'all') {
if(!validator.isLength(password, {min: 1})) {
setValidPassword(false);
setPasswordHelper('Password field cannot be empty');
allowSubmit = false;
} else if(!validator.isLength(password, {max: 200})) {
setValidPassword(false);
setPasswordHelper('Password exceeds maximum length of 200')
allowSubmit = false;
} else {
setValidPassword(true);
}
}
return allowSubmit;
}
// Checking if form is valid before submitting
const onSubmitHandler = () => {
if(validateForm('all')){
onLogin?.();
}
}
return (
<CardWrapper>
<Card.Content>
<TextInput
label="Email"
mode="outlined"
style={styles.textInput}
onChangeText={setEmail}
value={email}
dense
error={!validEmail}
onBlur={() => {validateForm('email')}}
/>
<HelperText
type="error"
visible={!validEmail}
style={{display: !validEmail ? undefined : 'none'}}
>
{emailHelper}
</HelperText>
<TextInput
label="Password"
mode="outlined"
style={{...styles.textInput, ...styles.marginTop}}
onChangeText={setPassword}
value={password}
dense
secureTextEntry={!isVisiblePassword}
onBlur={() => {validateForm('password')}}
right={
<TextInput.Icon
color={(isFocused) =>
validPassword
? (isFocused ? colors.primary : 'black')
: colors.error
}
forceTextInputFocus={false}
onPress={() => setIsVisiblePassword(!isVisiblePassword)}
name={isVisiblePassword ? "eye-off" : "eye"}
/>
}
error={!validPassword}
/>
<HelperText
type="error"
visible={!validPassword}
style={{display: !validPassword ? undefined : 'none'}}
>
{passwordHelper}
</HelperText>
<Button
style={{marginTop: 15}}
mode="contained"
onPress={onSubmitHandler}
loading={loading}
>
Login
</Button>
</Card.Content>
</CardWrapper>
);
};