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

使用Mantine+Yup实现多步表单 未校验通过仍跳转下一步问题

问题根因

你的判断完全正确:Next按钮的onClick回调直接执行了activeStep更新,没有触发任何当前步骤的字段校验逻辑。Mantine useForm 绑定的Yup校验默认只会在表单提交、手动调用校验API时触发,你给Next按钮同时绑定onClick跳步和type="submit"时,onClick逻辑会先执行,根本等不到校验跑完就已经切到下一步了。

修复方案

Mantine useForm 暴露了validate()方法,支持传入指定字段列表手动触发对应字段的校验,校验通过会返回true,失败会自动给对应字段绑定错误提示,完全适配你用的Yup规则。你只需要在跳步前先调用这个方法校验当前步骤字段,通过后再更新步骤状态即可,完整修复代码如下:

// 按步骤索引映射当前步骤需要校验的字段,后续新增步骤直接扩展该数组即可
const stepFieldMap = [
  ['email', 'password'], // 第0步:账号信息页校验字段
  ['firstName', 'lastName'] // 第1步:个人信息页校验字段
];

// 补全全量字段的Yup校验规则,避免最后提交时漏校验
const schema = yup.object().shape({
  email: yup.string().email('请输入有效的邮箱地址').required('邮箱不能为空'),
  password: yup.string().required('密码不能为空'),
  firstName: yup.string().required('名不能为空'),
  lastName: yup.string().required('姓不能为空')
});

function MultiStepForm() {
  const [activeStep, setActiveStep] = useState(0);
  const form = useForm({
    schema: yupResolver(schema),
    initialValues: {
      email: "",
      password: "",
      firstName: "",
      lastName: ""
    }
  });

  // 下一步按钮点击逻辑
  const handleNext = async () => {
    // 仅校验当前步骤的字段,不跑全量校验
    const currentStepValid = await form.validate(stepFieldMap[activeStep]);
    if (currentStepValid) {
      setActiveStep(prev => prev + 1);
    }
  };

  // 表单最终提交逻辑
  const handleFormSubmit = form.onSubmit((values) => {
    console.log('全表单校验通过,提交数据:', values);
    // 这里写接口提交逻辑即可
  });

  const isLastStep = activeStep === stepFieldMap.length - 1;

  return (
    <form onSubmit={handleFormSubmit}>
      <Paper shadow="xs" p="md">
        {activeStep === 0 && (
          <>
            <Title>账号信息</Title>
            <Group>
              <TextInput label="Email" {...form.getInputProps("email")} />
              <TextInput label="Password" {...form.getInputProps("password")} />
            </Group>
          </>
        )}

        {activeStep === 1 && (
          <>
            <Title>个人信息</Title>
            <Group>
              <TextInput label="First name" {...form.getInputProps("firstName")} />
              <TextInput label="Last name" {...form.getInputProps("lastName")} />
            </Group>
          </>
        )}

        <Group mt="xl">
          <Button
            onClick={() => setActiveStep(prev => prev - 1)}
            disabled={activeStep === 0}
          >
            上一步
          </Button>
          {/* 最后一步渲染提交按钮,前面步骤渲染带校验的下一步按钮 */}
          {isLastStep ? (
            <Button type="submit">提交</Button>
          ) : (
            <Button onClick={handleNext}>下一步</Button>
          )}
        </Group>
      </Paper>
    </form>
  );
}
核心改动点
  • 移除了Next按钮上同时绑定的onClick直接跳步和type="submit"的冲突逻辑,避免跳步优先级高于校验
  • 新增步骤字段映射表,后续扩展多步时只需要往数组里加对应字段列表即可,不需要修改核心校验逻辑
  • 非最后一步点击Next时,调用form.validate(当前步骤字段列表)异步校验当前字段,校验通过才更新步骤状态,校验失败会自动在对应输入框下方展示Yup配置的错误提示
  • 补全了个人信息步骤两个字段的Yup校验规则,避免最后提交时出现未校验的字段
  • 最后一步单独渲染提交按钮,触发全表单校验后执行提交逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 20:27:27