You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>
  );
}

关键说明

  1. Zod内部结构兼容性:虽然使用了Zod的内部API(_def、checks),但这些结构在Zod的稳定版本中变化极小,可放心使用;若担心版本更新,可关注Zod官方日志。
  2. 规则扩展:工具函数可按需扩展,比如添加对日期、布尔值的规则提取,或是对regex、email等特殊校验的处理(部分规则MUI组件无对应属性,可忽略)。
  3. 属性映射:确保提取的规则与MUI组件的属性名一致(比如Zod的min对应数字类型TextField的min属性,minLength对应字符串类型的minLength)。

内容的提问来源于stack exchange,提问作者Dominic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 18:15:08