如何为React Final Form嵌套输入编写正确的Zod验证Schema
动态增减输入项的表单Zod验证失效解决方法
问题核心原因
- Schema与表单字段不匹配:你定义的Zod Schema里,
field是包含label和value的对象,但表单中field是单选框的字符串值;conditions被定义为空对象,实际表单里是字符串值,还遗漏了表单中存在的operator字段定义。 - 遍历参数错误:
filterList.map((index) => ...)写法错误,map的第一个参数是数组元素,第二个才是索引,会导致字段命名的索引逻辑出错。 - 未设置必填约束:仅定义了数据结构,未给字段添加
min(1)或required()这类触发验证的规则,自然不会出现提示。
修正后的完整代码
import { useState } from 'react'; import { z } from 'zod'; const DynamicFilterForm = ({ initialValues = [] }) => { // 修正初始值判断逻辑,避免数组引用比较的错误 const [filterList, setFilterList] = useState( initialValues.length > 0 ? initialValues : [{ operator: "", field: "", conditions: "" }] ); // 匹配表单实际字段的Zod验证规则 const verifyInput = () => { return z.object({ filters: z.array( z.object({ operator: z.string().min(1, "操作符不能为空"), field: z.string().min(1, "请选择字段"), conditions: z.string().min(1, "请选择条件"), }) ).min(1, "至少需要添加一个筛选条件"), }); }; const handleFilterAdd = () => { setFilterList([...filterList, { operator: "", field: "", conditions: "" }]); }; const handleFilterRemoveAll = () => { setFilterList([{ operator: "", field: "", conditions: "" }]); }; return ( <Form schema={verifyInput()}> {filterList.map((_, index) => ( <div key={index}> <input id={`operator-${index}`} name={`filters[${index}].operator`} size="sm" type="text" placeholder="输入操作符" /> <select id={`field-${index}`} name={`filters[${index}].field`} placeholder="选择字段" > <option value="">请选择</option> <option value="volvo">Volvo</option> <option value="saab">Saab</option> </select> <select id={`conditions-${index}`} size="sm" name={`filters[${index}].conditions`} placeholder="选择条件" > <option value="">请选择</option> <option value="mercedes">Mercedes</option> <option value="audi">Audi</option> </select> </div> ))} <RemoveAllFiltersButton handleFilterRemoveAll={handleFilterRemoveAll} /> <Button onClick={handleFilterAdd} leftIcon={<FiPlus />}> Add Filter </Button> </Form> ); }; export default DynamicFilterForm;
关键优化点
- 给下拉框添加空选项,确保未选择时能触发必填验证;
- 为每个字段添加自定义错误提示,明确验证要求;
- 给
filters数组添加min(1)约束,保证至少存在一个筛选项; - 修正了
filterList初始化时的逻辑错误,避免无效判断。
内容的提问来源于stack exchange,提问作者coder29
相关产品推荐
相关产品推荐

