React Hook Form+Zod+MUI:如何从Schema获取字段校验规则?
解决方案:从Zod Schema提取校验规则同步到MUI组件
核心思路是直接解析Zod Schema的内部结构,提取字段的校验规则(必填、长度/数值范围等),然后将这些规则映射到MUI组件的对应属性上,实现单一Schema同时服务校验和输入限制。
步骤1:编写规则提取工具函数
Zod的Schema包含内部结构(_def、checks),可以通过这些结构获取字段的校验约束。我们封装一个工具函数统一处理:
// 从Zod Schema提取字段校验规则 const extractFieldRules = (schema, fieldName) => { const rules = {}; // 1. 判断字段是否为表单必填项(即Schema中未标记为optional) if (!schema._def.shape[fieldName].isOptional()) { rules.required = true; } const fieldDef = schema._def.shape[fieldName]._def; // 2. 提取字符串类型规则(minLength/maxLength) if (fieldDef.typeName === 'ZodString') { fieldDef.checks.forEach(check => { switch (check.kind) { case 'min': rules.minLength = check.value; break; case 'max': rules.maxLength = check.value; break; } }); } // 3. 提取数字类型规则(min/max) if (fieldDef.typeName === 'ZodNumber') { fieldDef.checks.forEach(check => { switch (check.kind) { case 'min': rules.min = check.value; break; case 'max': rules.max = check.value; break; } }); } return rules; };
步骤2:在Controller中使用工具函数
在Controller的render回调里,调用工具函数提取当前字段的规则,直接传递给MUI组件:
import { z } from 'zod'; import { useForm, Controller } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import TextField from '@mui/material/TextField'; // 定义Zod Schema const testSchema = z.object({ employer: z.string().min(2).max(50), salary: z.number().min(0).max(100000), email: z.string().email().optional() }); type FormData = z.infer<typeof testSchema>; export default function IncomeForm() { const { handleSubmit, control } = useForm<FormData>({ resolver: zodResolver(testSchema), defaultValues: { employer: '', salary: 0, email: '' } }); const onSubmit = (data: FormData) => { console.log('表单数据:', data); }; return ( <form onSubmit={handleSubmit(onSubmit)}> <Controller name="employer" control={control} render={({ field, fieldState }) => { const fieldRules = extractFieldRules(testSchema, 'employer'); return ( <TextField {...field} {...fieldRules} label="雇主名称" error={!!fieldState.error} helperText={fieldState.error?.message} fullWidth margin="normal" /> ); }} /> <Controller name="salary" control={control} render={({ field, fieldState }) => { const fieldRules = extractFieldRules(testSchema, 'salary'); return ( <TextField {...field} {...fieldRules} label="薪资" type="number" error={!!fieldState.error} helperText={fieldState.error?.message} fullWidth margin="normal" /> ); }} /> <button type="submit" style={{ marginTop: 16 }}>提交</button> </form> ); }
关键说明
- Zod内部结构兼容性:虽然使用了Zod的内部API(
_def、checks),但这些结构在Zod的稳定版本中变化极小,可放心使用;若担心版本更新,可关注Zod官方日志。 - 规则扩展:工具函数可按需扩展,比如添加对日期、布尔值的规则提取,或是对regex、email等特殊校验的处理(部分规则MUI组件无对应属性,可忽略)。
- 属性映射:确保提取的规则与MUI组件的属性名一致(比如Zod的
min对应数字类型TextField的min属性,minLength对应字符串类型的minLength)。
内容的提问来源于stack exchange,提问作者Dominic
相关产品推荐
相关产品推荐

