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

如何在Formik中实现Yup自定义验证validateGroup的条件触发

解决方案:Formik中仅在提交时执行带API调用的自定义校验

核心思路是拆分校验逻辑:实时校验仅处理必填规则(避免频繁触发API),带API调用的自定义校验只在点击提交按钮时执行,同时保留原需求中「仅当title和description都不为空时才校验group有效性」的条件。

1. 调整Validation Schema

移除原Schema中绑定到实时校验的validateGroup,只保留必填规则,避免输入时触发API:

const validationSchema = Yup.object().shape({
  tasks: Yup.array().of(
    Yup.object().shape({
      title: Yup.string().required("Required"),
      description: Yup.string().required("Required"),
      group: Yup.string().required("Required")
      // 移除原when逻辑中的validateGroup,防止实时触发API
    })
  )
});

2. 在提交阶段手动执行自定义校验

利用Formik的onSubmit钩子,在点击提交按钮时手动调用带API的validateGroup,并处理错误信息:

import { Formik, Form, Field, FieldArray } from 'formik';
import * as Yup from 'yup';

// 带API调用的自定义校验函数
const validateGroup = async (groupValue) => {
  // 示例API调用,替换为你的实际接口逻辑
  const response = await fetch(`/api/validate-group?group=${groupValue}`);
  const isValid = await response.json();
  if (!isValid) {
    throw new Error("Input valid group");
  }
};

const TaskForm = () => {
  return (
    <Formik
      initialValues={{ tasks: [{ title: '', description: '', group: '' }] }}
      validationSchema={validationSchema}
      onSubmit={async (values, { setErrors, setSubmitting, validateForm }) => {
        // 先执行Yup的必填校验,确保基础规则通过
        const baseErrors = await validateForm();
        if (Object.keys(baseErrors).length > 0) {
          setErrors(baseErrors);
          setSubmitting(false);
          return;
        }

        // 初始化提交错误对象
        const submitErrors = { tasks: [] };
        let hasValidationError = false;

        // 遍历每个任务,执行自定义校验
        for (let i = 0; i < values.tasks.length; i++) {
          const task = values.tasks[i];
          submitErrors.tasks[i] = {};

          // 满足原需求条件:title和description都不为空时才校验group
          if (task.title && task.description) {
            try {
              await validateGroup(task.group);
            } catch (err) {
              submitErrors.tasks[i].group = err.message;
              hasValidationError = true;
            }
          }
        }

        // 存在校验错误时,设置错误并终止提交
        if (hasValidationError) {
          setErrors(submitErrors);
          setSubmitting(false);
          return;
        }

        // 校验通过,执行实际提交逻辑
        console.log('提交数据:', values);
        // 替换为你的提交API调用
        setSubmitting(false);
      }}
    >
      {({ errors, touched }) => (
        <Form>
          <FieldArray name="tasks">
            {({ push, remove }) => (
              <>
                {values.tasks.map((_, index) => (
                  <div key={index} className="task-row">
                    <div>
                      <label>Title</label>
                      <Field name={`tasks[${index}].title`} />
                      {errors.tasks?.[index]?.title && touched.tasks?.[index]?.title && (
                        <span className="error">{errors.tasks[index].title}</span>
                      )}
                    </div>
                    <div>
                      <label>Description</label>
                      <Field name={`tasks[${index}].description`} />
                      {errors.tasks?.[index]?.description && touched.tasks?.[index]?.description && (
                        <span className="error">{errors.tasks[index].description}</span>
                      )}
                    </div>
                    <div>
                      <label>Group</label>
                      <Field name={`tasks[${index}].group`} />
                      {/* 同时显示必填错误和提交时的自定义校验错误 */}
                      {errors.tasks?.[index]?.group && touched.tasks?.[index]?.group && (
                        <span className="error">{errors.tasks[index].group}</span>
                      )}
                    </div>
                    <button type="button" onClick={() => remove(index)}>删除</button>
                  </div>
                ))}
                <button type="button" onClick={() => push({ title: '', description: '', group: '' })}>添加任务</button>
              </>
            )}
          </FieldArray>
          <button type="submit">提交表单</button>
        </Form>
      )}
    </Formik>
  );
};

export default TaskForm;

关键说明

  • 实时校验仅由Yup处理必填规则,不会触发任何API调用,避免接口频繁请求
  • 提交时先通过validateForm()确保所有必填项已填写,再执行带API的自定义校验
  • 自定义校验仅在满足title和description非空的条件下执行,符合原需求逻辑
  • 校验错误通过setErrors同步到Formik状态,自动在表单中展示错误提示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 17:31:03