React中Formik+Yup密码验证:一次性展示所有错误并逐步消除
实现Formik+Yup密码多规则验证并批量展示/移除错误提示
要实现一次性展示所有密码验证错误,且满足规则后逐步移除提示,需要两步核心操作:关闭Yup的提前终止验证,以及调整验证规则确保所有规则都被检查并收集错误,具体实现如下:
1. 配置Formik禁用提前终止验证
Yup默认开启abortEarly: true,意味着只要遇到第一个验证失败就停止后续检查,所以必须在Formik配置中显式设置abortEarly: false,确保所有验证规则都能执行并收集所有错误。
用Formik组件示例:
import { Formik, Form, Field } from 'formik'; import * as Yup from 'yup'; // 后续定义userSchema... <Formik initialValues={{ password: '' }} validationSchema={userSchema} abortEarly={false} // 关键配置:不提前终止验证 validateOnChange={true} // 实时验证,输入时更新错误状态 validateOnBlur={true} onSubmit={(values) => { console.log('Submitted:', values); }} > {({ errors, touched }) => ( <Form> {/* 表单渲染内容 */} </Form> )} </Formik>
用useFormik Hook示例:
import { useFormik } from 'formik'; import * as Yup from 'yup'; const formik = useFormik({ initialValues: { password: '' }, validationSchema: userSchema, abortEarly: false, validateOnChange: true, onSubmit: (values) => { console.log('Submitted:', values); }, });
2. 调整Yup验证规则,收集所有错误
默认的链式验证(如.min().matches())会在第一个失败时停止,无法收集所有不满足的规则错误。我们可以用test方法自定义验证逻辑,一次性检查所有规则并返回所有错误消息。
自定义验证函数+Yup test:
// 自定义密码验证逻辑,返回所有不满足的错误消息 const validatePasswordRules = (value) => { const errorMessages = []; // 规则1:至少12个字符 if (!value || value.length < 12) { errorMessages.push('At least 12 characters long'); } // 规则2:同时包含大小写字母 if (!value || !(/[A-Z]/.test(value) && /[a-z]/.test(value))) { errorMessages.push('Mix of uppercase and lowercase letters'); } // 规则3:至少包含一位数字 if (!value || !/[0-9]/.test(value)) { errorMessages.push('At least one digit (0-9)'); } // 规则4:至少包含一个特殊字符 if (!value || !/[!%&@#$^*?_~.,]/.test(value)) { errorMessages.push('At least one special character (!%&@#$^*?_~.,)'); } return errorMessages; }; // 定义Yup Schema const userSchema = Yup.object({ password: Yup.string() .test( 'password-all-rules', 'Password validation failed', (value) => { const errors = validatePasswordRules(value); if (errors.length > 0) { // 抛出包含所有错误的ValidationError throw new Yup.ValidationError(errors, value, 'password'); } return true; } ) });
3. 渲染所有错误提示
现在errors.password会是一个包含所有未满足规则的错误数组,我们可以遍历它来展示每一条错误,当用户输入满足某条规则时,该错误会自动从数组中移除:
<div className={styles.field_outer_wrapper}> <div className={styles.field_inner_wrapper}> <label htmlFor="password" className={styles.label}> Password* </label> <Field name="password" id="password" type="password" className={`${styles.text_field} ${touched.password && errors.password ? styles.alert : ''}`} /> {/* 渲染所有错误提示 */} {touched.password && errors.password && ( <div className={styles.error_container}> {errors.password.map((error, idx) => ( <div key={idx} className={styles.error_item}> • {error} </div> ))} </div> )} </div> </div>
关键说明
abortEarly: false是核心,确保Formik收集所有验证错误- 自定义
test方法让所有规则都被检查,不会因某条规则失败而跳过其他 validateOnChange: true保证用户输入时实时验证,错误提示会随输入动态更新(满足规则的错误自动消失)
内容的提问来源于stack exchange,提问作者Jonas
相关产品推荐
相关产品推荐

