如何使用yup与react-hook-form验证多账号登录表单的数组对象字段
基于Yup实现多组账号表单验证问题排查
我最近开始使用Yup做表单验证,重写登录页时遇到了问题:该页面会根据用户持有的账号数量展示多组登录名、密码字段。
原有的验证逻辑运行正常,但我们希望改用Yup实现对应能力。我编写了简单的Yup验证schema但无法正常运行,恳请大家协助排查问题,如有需要补充的信息可以告知我。

预期效果
- 新增输入字段时,Yup能自动生成对应的验证规则
- 单独验证数组内每个对象的字段:目前测试发现下面的示例数组会被整体判定验证失败,我只希望第一个对象的
login_name单独验证失败
const invalid_example = [ { login_name: '' login_password: 'value' }, { login_name: 'value' login_password: 'value' }];
代码示例
state定义
const [validation, setValidation] = useState({ users: [{ login_name: "notActive", login_password: "notActive" }] }); const [login, setLogin] = useState({ users: [{ login_name: "", login_password: "" }], });
输入字段渲染
{login.users.map((item, i) => ( <Grid container direction="row" key={i} spacing={1}> <Grid item xs={5} sm={5} md={5} lg={5} xl={5}> <TextField {...register(`users.${i}.login_name`, { shouldUnregister: true })} id={i} variant="outlined" type="text" name={`users${[i]}.login_name`} value={login.users.login_name} onChange={(e) => handleChange(e, i)} label={props.t("login:Your Login Name")} error={ Object.keys(errors).length > 0 ? errors.users[i].login_name.message !== undefined : validation.users[i].login_name === false } helperText={ Object.keys(errors).length > 0 ? props.t(`register:${errors.users[i].login_name.message}`) : validation.users[i].login_name === false && props.t("login:LoginName") } fullWidth required /> </Grid> <Grid item xs={5} sm={5} md={5} lg={5} xl={5}> <TextField {...register(`users.${i}.login_password`, { shouldUnregister: true })} id={i} variant="outlined" type="password" name={`users${[i]}.login_password`} value={login.users.login_password} onChange={(e) => handleChange(e, i)} label={props.t("login:Your Password")} error={ Object.keys(errors).length > 0 ? errors.users[i].login_password.message !== undefined : validation.users[i].login_password === false } helperText={ Object.keys(errors).length > 0 ? props.t(`register:${errors.users[i].login_password.message}`) : validation.users[i].login_password === false && props.t("login:Password") } fullWidth required /> </Grid> </Grid> ))}
handleChange函数
const handleChange = (e, i) => { const { name, value} = e.target; const username = name.split('.', 3)[1] let users = [...login.users]; users[i] = { ...users[i], [username]: value }; setLogin({ users: users }); if (username === "login_name" || username === "login_password") { let val = [...validation.users]; let newName = username === "login_password" ? "login_name" : "login_password"; let newValue = username === "login_password" ? val[i].login_name : val[i].login_password; if (value === "") { val[i] = { ...users[i], [username]: false, [newName]: newValue }; setValidation({ users: val }); } else { val[i] = { ...users[i], [username]: true, [newName]: newValue }; setValidation({ users: val }); } } }
Yup验证schema
const LoginSchema = yup.object().shape({ users: yup.array().ensure().of( yup.object().shape({ login_name: yup.string().required(empty_field), login_password: yup.string().required(empty_field), })).required(empty_field) });
当前存在的问题
- 只要有一个字段为空,整个登录表单就会验证失败,需要实现每个字段单独校验
- 当所有字段都填写了有效值时,表单无法验证通过
- 触发表单验证后再新增登录字段会报错,Yup只会读取验证前已存在的对象规则,不会适配新增字段
修复方案
1. 统一字段命名
你在register里用的字段名是users.${i}.login_name,但手动给TextField绑定的name是users${[i]}.login_name,两者格式不一致导致Yup无法正确匹配验证结果,直接修改TextField的name属性即可:
// 登录名字段修改 name={`users.${i}.login_name`} // 密码字段同理修改 name={`users.${i}.login_password`}
2. 移除冲突的自定义验证逻辑
你同时使用了React Hook Form的内置验证和自定义的validation状态控制错误显示,两者逻辑冲突会导致验证结果异常。建议直接使用React Hook Form返回的errors对象判断错误状态,删除自定义的validation相关state和handleChange里的validation修改逻辑:
// 错误状态判断简化为 error={!!errors?.users?.[i]?.login_name} // 提示文案同理简化 helperText={errors?.users?.[i]?.login_name ? props.t(`register:${errors.users[i].login_name.message}`) : ''}
3. 适配新增字段验证
你已经配置了shouldUnregister: true,字段卸载时会自动注销验证规则,新增字段时只要保证新增的users数组项结构符合schema要求,Yup会自动适配新增项的验证规则,新增账号的逻辑可参考如下写法:
const addUser = () => { setLogin(prev => ({ ...prev, users: [...prev.users, { login_name: "", login_password: "" }] })) }
4. Schema优化
现有schema结构无需修改,只需提前定义好empty_field对应的错误提示字符串即可,修改后所有数组项会独立校验,单个字段错误不会影响其他正常填写的账号项。
内容的提问来源于stack exchange,提问作者DCCW
相关产品推荐
相关产品推荐

