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

如何在react-hook-form的handleSubmit中同步执行自定义验证?

解决React Hook Form中自定义验证与内置验证错误同时显示的问题

你可以通过两种方式实现自定义验证与yup内置验证错误的同时显示,核心是将自定义验证的错误整合到React Hook Form的errors对象中,或者把自定义验证逻辑融入yup的schema里。

方案一:手动控制验证流程,统一管理错误

通过setError将自定义验证错误添加到表单错误集合,同时用trigger触发所有字段的内置验证,确保两类错误同时被渲染:

import { useState } from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";

// 原有的yup验证schema
const validationFormSchema = yup.object().shape({
  name: yup.string().required("请输入产品名称"),
});

const Form = () => {
  const [selectedImages, setSelectedImages] = useState([]);
  const formOptions = { resolver: yupResolver(validationFormSchema) };
  const {
    register,
    formState: { errors },
    setError,
    clearErrors,
    trigger,
    getValues,
  } = useForm(formOptions);

  const handleAddImg = (e) => {
    const fileListArrayImg = Array.from(e.target.files);
    setSelectedImages(fileListArrayImg);
  };

  // 自定义图片验证函数,返回错误信息(无错误则返回null)
  const validateImgs = (images) => {
    if (images.length === 0) return "请至少选择一张图片";
    for (const img of images) {
      if (img.size > 2 * 1024 * 1024) {
        return `图片${img.name}大小不能超过2MB`;
      }
      if (!["image/png", "image/jpeg"].includes(img.type)) {
        return `图片${img.name}格式必须为PNG或JPEG`;
      }
    }
    return null;
  };

  const customSubmit = async () => {
    // 清除之前的图片错误
    clearErrors("image");
    // 执行图片验证
    const imgErrorMsg = validateImgs(selectedImages);
    if (imgErrorMsg) {
      setError("image", { message: imgErrorMsg });
    }
    // 触发所有字段的内置yup验证
    const isFormValid = await trigger();
    // 只有两类验证都通过,才执行提交逻辑
    if (isFormValid && !imgErrorMsg) {
      const formData = getValues();
      // 这里写你的提交逻辑
      console.log("提交表单数据:", formData, selectedImages);
    }
  };

  return (
    <form
      encType="multipart/form-data"
      onSubmit={(e) => {
        e.preventDefault();
        customSubmit();
      }}
    >
      <input type="text" {...register("name")} placeholder="产品名称" />
      <span style={{ color: "red" }}>{errors.name?.message}</span>

      <input
        type="file"
        multiple
        accept="image/png, image/jpeg"
        onChange={handleAddImg}
      />
      <span style={{ color: "red" }}>{errors.image?.message}</span>

      <button type="submit">提交</button>
    </form>
  );
};

export default Form;

方案二:将自定义验证整合到Yup Schema中(推荐)

把图片验证逻辑直接写到yup的schema里,让yupResolver统一处理所有验证,无需手动控制提交流程:

import { useState } from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";

const Form = () => {
  const [selectedImages, setSelectedImages] = useState([]);
  // 整合了图片验证的yup schema
  const validationFormSchema = yup.object().shape({
    name: yup.string().required("请输入产品名称"),
    image: yup.array().test(
      "image-validation",
      "",
      (value) => {
        if (value.length === 0) {
          return new yup.ValidationError("请至少选择一张图片", value, "image");
        }
        for (const img of value) {
          if (img.size > 2 * 1024 * 1024) {
            return new yup.ValidationError(
              `图片${img.name}大小不能超过2MB`,
              value,
              "image"
            );
          }
          if (!["image/png", "image/jpeg"].includes(img.type)) {
            return new yup.ValidationError(
              `图片${img.name}格式必须为PNG或JPEG`,
              value,
              "image"
            );
          }
        }
        return true;
      }
    ),
  });

  const formOptions = {
    resolver: yupResolver(validationFormSchema),
    defaultValues: { name: "", image: [] },
  };
  const {
    register,
    handleSubmit,
    formState: { errors },
    setValue,
  } = useForm(formOptions);

  const handleAddImg = (e) => {
    const fileListArrayImg = Array.from(e.target.files);
    setSelectedImages(fileListArrayImg);
    // 将选中的图片同步到表单字段中,供yup验证
    setValue("image", fileListArrayImg);
  };

  const submitFunction = async (formData) => {
    // 此时所有验证已通过,直接执行提交逻辑
    console.log("提交表单数据:", formData);
  };

  return (
    <form encType="multipart/form-data" onSubmit={handleSubmit(submitFunction)}>
      <input type="text" {...register("name")} placeholder="产品名称" />
      <span style={{ color: "red" }}>{errors.name?.message}</span>

      <input
        type="file"
        multiple
        accept="image/png, image/jpeg"
        onChange={handleAddImg}
      />
      <span style={{ color: "red" }}>{errors.image?.message}</span>

      <button type="submit">提交</button>
    </form>
  );
};

export default Form;

说明

  • 两种方案都能让yup内置验证错误和自定义图片验证错误同时显示,因为所有错误都被整合到React Hook Form的errors对象中。
  • 方案二更贴合React Hook Form与yup的集成设计,将所有验证逻辑集中管理,代码更简洁。
  • 你之前尝试的写法问题在于:自定义验证的错误没有被添加到表单的errors集合中,且handleSubmit仍会优先执行内置验证,导致两类错误无法同时触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 15:24:21