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

React-hook-form问题:表单提交后错误消息不显示,需手动刷新

问题描述

使用react-hook-form结合yup做表单字段校验,通过<ErrorMessage>组件展示多条错误消息。遇到的问题:提交表单后立即在字段中输入无效内容,错误消息无法显示;但提交按钮会被禁用,说明校验逻辑已经触发,只是错误消息没渲染出来。手动刷新页面后,错误消息又能正常显示。

原始代码片段
import React, { useState } from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import { ErrorMessage } from "@hookform/error-message";
import validationSchema from "../validations/validationSchema";

export default function Report(props) {
  const {
    register,
    handleSubmit,
    formState: { errors, isValid },
  } = useForm({
    mode: "onBlur",
    // reValidateMode: "onChange",
    criteriaMode: "all",
    resolver: yupResolver(validationSchema),
    defaultValues: {
      closedBugs: "",
    },
  });

  const [state, setState] = useState({
    closedBugs: "",
    reportedIncidents: "",
    reportedBugs: "",
  });

  const onFormSubmit = (data, event) => {
    event.preventDefault();
    props.onSubmit(state);
  };

  // 补全原代码缺失的handleChange函数
  const handleChange = (key, value) => {
    setState({
      ...state,
      [key]: value,
    });
  };

  const modifyBugsValues = (value) => {
    if (value === "") {
      // 为空时返回undefined,让yup触发必填校验
      return undefined;
    } else {
      // 替换逗号为点,让yup识别为数字进行整数校验
      value = value.replace(/,/g, ".");
      return value;
    }
  };

  return (
    <div className="container">
      <div className="ui segment report">
        <form onSubmit={handleSubmit(onFormSubmit)} className="ui form">
          <h4 className="ui dividing header">Project information</h4>
          <h4 className="ui dividing header">Bug metrics</h4>
          <div className="three fields">
            <div className="field mandatory-metric">
              <label>closed bugs during month</label>
              <div className="field">
                <input
                  type="text"
                  {...register("closedBugs", {
                    setValueAs: modifyBugsValues,
                  })}
                  onChange={(e) => handleChange(e.target.name, e.target.value)}
                  name="closedBugs"
                  placeholder="1"
                  required
                />

                <ErrorMessage
                  errors={errors}
                  name="closedBugs"
                  render={({ messages }) => {
                    console.log("Messages" + JSON.stringify(messages));
                    return (
                      messages &&
                      Object.entries(messages).map(([type, message]) => (
                        <p className="error" key={type}>
                          {message}
                        </p>
                      ))
                    );
                  }}
                />
              </div>
            </div>
          </div>
          <button
            type="submit"
            className="ui secondary large button"
            data-cy="submitBtn"
            disabled={!isValid}
            tabIndex={0}
          >
            Submit report
          </button>
        </form>
      </div>
    </div>
  );
}
问题原因与修复方案

核心问题

你同时使用了react-hook-form的内置状态管理和自定义本地useState,两者状态不同步:提交表单后,react-hook-form的内部状态已标记为提交状态,但自定义的onChange仅更新本地state,未同步到react-hook-form的内部状态,导致errors对象无法及时更新,<ErrorMessage>组件拿不到最新错误信息。另外,当前mode: "onBlur"和注释掉的reValidateMode设置,也导致输入内容变化时无法实时触发校验更新错误。

具体修复步骤

  1. 移除本地state和自定义onChange
    react-hook-form已内置完整的表单状态管理,无需自行维护state和handleChange,提交时直接使用react-hook-form返回的校验后data即可。

  2. 开启实时校验模式
    设置reValidateMode: "onChange",让输入内容变化时实时触发校验,确保errors对象及时更新,错误消息同步显示。

  3. 移除input上的required属性
    yup的校验规则已包含必填校验,重复设置required会导致逻辑冲突。

修复后的代码

import React from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import { ErrorMessage } from "@hookform/error-message";
import validationSchema from "../validations/validationSchema";

export default function Report(props) {
  const {
    register,
    handleSubmit,
    formState: { errors, isValid },
  } = useForm({
    mode: "onBlur",
    reValidateMode: "onChange", // 开启输入时实时校验
    criteriaMode: "all",
    resolver: yupResolver(validationSchema),
    defaultValues: {
      closedBugs: "",
      reportedIncidents: "",
      reportedBugs: "",
    },
  });

  const onFormSubmit = (data) => {
    // 直接使用react-hook-form返回的校验后数据
    props.onSubmit(data);
  };

  const modifyBugsValues = (value) => {
    if (value === "") {
      return undefined;
    } else {
      return value.replace(/,/g, ".");
    }
  };

  return (
    <div className="container">
      <div className="ui segment report">
        <form onSubmit={handleSubmit(onFormSubmit)} className="ui form">
          <h4 className="ui dividing header">Project information</h4>
          <h4 className="ui dividing header">Bug metrics</h4>
          <div className="three fields">
            <div className="field mandatory-metric">
              <label>closed bugs during month</label>
              <div className="field">
                <input
                  type="text"
                  {...register("closedBugs", {
                    setValueAs: modifyBugsValues,
                  })}
                  name="closedBugs"
                  placeholder="1"
                />

                <ErrorMessage
                  errors={errors}
                  name="closedBugs"
                  render={({ messages }) => {
                    return (
                      messages &&
                      Object.entries(messages).map(([type, message]) => (
                        <p className="error" key={type}>
                          {message}
                        </p>
                      ))
                    );
                  }}
                />
              </div>
            </div>
          </div>
          <button
            type="submit"
            className="ui secondary large button"
            data-cy="submitBtn"
            disabled={!isValid}
            tabIndex={0}
          >
            Submit report
          </button>
        </form>
      </div>
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 23:27:43