Formik与Yup校验问题:字符串及日期数组字段验证方案咨询
Yup表单校验问题解决
问题回顾
我有两个字段:字符串字段prod和日期数组字段date,用Yup校验时碰到两个问题:
oneOf和自定义test都没法校验prod是否在指定字符串数组里;- 日期字段为空时,
prod的“required”错误会被触发。
需求明确:
prod:非空且值必须在给定字符串数组内;date:非空且必须包含两个日期。
当前使用的代码:
const myArray = useMemo(() => someData.map(({ value }) => value), [someData]); // string[] const schema = yup.object({ prod: yup .string() .ensure() .oneOf(myArray, 'not in list') // 不生效 .required('add prod') // 其他字段为空也触发这个提示 :( .test( // 不生效 'prod', 'not in list 2', () => !!myArray.find((prod) => prod === myForm.values.prod) ), date: yup.array().required().min(1, 'add date').length(2, 'add second date'), });
问题原因
oneOf和自定义test失效:- 自定义
test直接依赖外部的myForm.values.prod,不符合Yup校验逻辑——校验函数应使用传入的value参数,而非外部表单状态,否则会导致校验触发时机或结果错误。 .ensure()会把undefined转为空字符串,若myArray不含空字符串,oneOf会报错,但后续.required()的逻辑会造成校验流程混乱。
- 自定义
- 跨字段触发required提示:
- 日期数组校验写法不严谨,未明确元素类型;且表单整体校验时,若
prod初始值为空,任何字段校验失败都会触发prod的required校验(表单库会重新校验所有字段)。
- 日期数组校验写法不严谨,未明确元素类型;且表单整体校验时,若
修正后的Schema
const myArray = useMemo(() => someData.map(({ value }) => value), [someData]); const schema = yup.object({ prod: yup .string() .required('请选择产品') // 先校验必填,再校验范围 .oneOf(myArray, '所选产品不在允许列表中'), date: yup .array() .of(yup.date().required('日期不能为空')) // 明确数组元素是有效日期 .required('请选择两个日期') .length(2, '必须选择两个日期'), });
额外说明
- 去掉
.ensure():required()会直接捕获undefined或空字符串,无需转义,让校验逻辑更清晰。 - 自定义
test替代方案(如果需要):
必须使用校验函数的.test( 'prod-in-list', '所选产品不在允许列表中', (value) => myArray.includes(value) )value参数,避免依赖外部状态。 - 日期数组校验优化:
.length(2)已经确保数组有两个元素,无需额外min(1),加上.of(yup.date())能保证每个元素都是有效的日期类型。
内容的提问来源于stack exchange,提问作者Will Black
相关产品推荐
相关产品推荐

