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

React Hook Form Controller 受控输入警告及表单提交异常排查

问题解决指南

1. 解决Input组件的受控/非受控警告

原因

react-hook-form默认字段初始值为undefined,Input组件直接绑定value={value}时,输入内容会让值从undefined变为字符串,触发React的受控组件警告。

修复方案

  • 步骤1:给useForm设置默认初始值
    在useForm初始化时添加defaultValues,明确字段初始状态:

    const {
      register,
      handleSubmit,
      formState: { errors },
      reset,
      control,
    } = useForm({
      defaultValues: {
        customSelect: null, // 适配react-select的空值格式
        Input: "" // Input初始值设为空字符串,避免undefined
      }
    });
    
  • 步骤2:Input组件处理空值兜底
    在Input组件的原生input标签中,给value添加空值兜底:

    <input
      // 其他属性不变
      value={value || ""}
      // 其他属性不变
    />
    

2. 解决提交表单无数据输出的问题

原因

Input组件没有传递onBlur事件给原生input,导致react-hook-form无法正确完成字段值的同步和校验触发。

修复方案

  • 步骤1:Input组件接收并绑定onBlur
    修改Input组件的props定义和原生input的绑定:
    // Input组件的props参数添加onBlur
    const Input = forwardRef(
      (
        {
          label,
          type,
          value,
          disabled,
          placeholder,
          name,
          register,
          errors,
          required,
          validationSchema,
          onChange,
          onBlur // 新增接收onBlur
        },
        ref
      ) => {
        // ...其他代码不变
        return (
          <div className="flex flex-col">
            {/* ...其他代码不变 */}
            <input
              // 其他属性不变
              onBlur={(e) => {
                e.target.style.borderColor = inputStyles.borderColor;
                e.target.style.borderWidth = "1px";
                onBlur?.(); // 调用Controller传递的onBlur
              }}
              // 其他属性不变
            />
            {/* ...其他代码不变 */}
          </div>
        );
      }
    );
    

3. 解决提交后错误提示不消失的问题

原因

  • 默认校验模式为onSubmit,仅在提交时校验,后续输入不会自动重新校验清除错误
  • reset()默认不会清除errors状态

修复方案

  • 步骤1:设置实时校验模式
    在useForm初始化时添加mode配置,让校验在输入变化时触发:

    const {
      register,
      handleSubmit,
      formState: { errors },
      reset,
      control,
    } = useForm({
      defaultValues: {
        customSelect: null,
        Input: ""
      },
      mode: "onChange" // 输入变化时自动校验,实时更新错误状态
    });
    
  • 步骤2:提交后重置表单并清除错误
    修改onSubmitted函数,调用reset()时传递默认值,确保错误状态被清除:

    const onSubmitted = (data, e) => {
      console.log(data);
      console.log(errors.Input);
      reset({
        customSelect: null,
        Input: ""
      }); // 显式传递默认值,确保表单和错误状态重置
    };
    

完整修改后的关键代码片段

Form组件修改后

import { useForm, Controller } from "react-hook-form";
import CustomSelect from "../Select/Select";
import Input from "../Input/Input";
import Button from "../Button/Button";

const Form = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
    reset,
    control,
  } = useForm({
    defaultValues: {
      customSelect: null,
      Input: ""
    },
    mode: "onChange"
  });

  const onSubmitted = (data, e) => {
    console.log(data);
    console.log(errors.Input);
    reset({
      customSelect: null,
      Input: ""
    });
  };

  return (
    // ...原有JSX结构不变
  );
};

Input组件修改后

import { forwardRef } from "react";

const Input = forwardRef(
  (
    {
      label,
      type,
      value,
      disabled,
      placeholder,
      name,
      register,
      errors,
      required,
      validationSchema,
      onChange,
      onBlur
    },
    ref
  ) => {
    const inputStyles = {
      backgroundColor: disabled ? "#f0f4f8" : "#ffffff",
      color: disabled ? "#6b7280" : "#000000",
      borderColor: disabled ? "#e5e7eb" : "#a0aec0",
    };

    const focusStyles = {
      borderColor: "#2563eb",
      borderWidth: "2px",
    };

    return (
      <div className="flex flex-col">
        <label>
          <span className="text-sm dark:text-gray-900">{label}</span>
        </label>
        <input
          type={type}
          name={name}
          className="h-9 border rounded p-2 outline-none"
          style={{ ...inputStyles }}
          value={value || ""}
          onChange={onChange}
          disabled={disabled}
          placeholder={placeholder}
          onFocus={(e) => {
            e.target.style.borderColor = focusStyles.borderColor;
            e.target.style.borderWidth = focusStyles.borderWidth;
          }}
          onBlur={(e) => {
            e.target.style.borderColor = inputStyles.borderColor;
            e.target.style.borderWidth = "1px";
            onBlur?.();
          }}
          ref={ref}
        />
        {errors && errors[name]?.type === "required" && (
          <span className="error">{errors[name]?.message}</span>
        )}
      </div>
    );
  }
);

export default Input;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 09:54:53