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

如何用React+React Hook Form+Yup创建可复用表单组件及解决Ref报错

问题解决:React Hook Form 结合自定义 InputGroup 组件的 Ref 错误

错误原因

你遇到的Warning: Unexpected ref object provided for input错误,是因为错误地将React Hook Form的register返回对象直接赋值给了自定义组件的ref属性。register返回的是包含ref、name、onChange等属性的对象,需要将这些属性全部传递给组件,而非仅作为ref使用。同时原自定义组件未支持传入子元素(如密码显示按钮的InputLeftElement),导致结构错误。

分步修复

1. 修改自定义InputGroups组件

更新组件以支持接收并传递表单相关属性,同时支持子元素渲染:

import { Input, InputGroup, InputRightElement } from "@chakra-ui/react";
import { forwardRef } from "react";

const InputGroups = forwardRef(({ size, type, placeholder, icon, children, ...rest }, ref) => {
  return (
    <InputGroup my={4} size={size}>
      {/* 渲染传入的左侧元素(如密码显示按钮) */}
      {children}
      <Input
        ref={ref}
        variant="filled"
        pr={10}
        type={type}
        placeholder={placeholder}
        {...rest} // 传递register返回的name、onChange、onBlur等核心属性
      />
      <InputRightElement>{icon}</InputRightElement>
    </InputGroup>
  );
});

export default InputGroups;

2. 修复Login组件的表单绑定

  • 正确传递register返回的所有属性给InputGroups组件
  • 补全缺失的导入(useState、InputLeftElement)
  • 添加表单验证错误提示
import { useState } from "react";
import { useForm } from "react-hook-form";
import * as Yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import { Button, useToast, InputLeftElement } from "@chakra-ui/react";
import InputGroups from "./InputGroups"; // 根据你的文件路径调整

const schema = Yup.object().shape({
  personalNumber: Yup.number().required("请输入您的号码"),
  password: Yup.string().required("请输入密码"),
});

const Login = () => {
  const toast = useToast({
    containerStyle: {
      marginTop: "40px",
    },
  });
  const [show, setShow] = useState(false);
  const showPasswordHandleClick = () => setShow(!show);

  const { register, handleSubmit, formState: { errors } } = useForm({ 
    resolver: yupResolver(schema),
    defaultValues: {
      personalNumber: "",
      password: ""
    }
  });

  const onSubmitHandler = (data) => {
    toast({
      title: "登录成功",
      status: "success",
      duration: 9000,
      isClosable: true,
      position: "top-right",
    });
    console.log(data);
  };

  return (
    <form
      className="login-form"
      style={{ textAlign: "center" }}
      onSubmit={handleSubmit(onSubmitHandler)}
    >
      <InputGroups
        size="md"
        type="number"
        placeholder="Type Your Number Code"
        icon={
          <i className="ki-duotone ki-sms">
            <i className="path1"></i>
            <i className="path2"></i>
          </i>
        }
        {...register("personalNumber")} // 传递register的所有属性
      />
      {/* 显示验证错误 */}
      {errors.personalNumber && (
        <p style={{ color: "red", margin: "0 0 10px 0" }}>{errors.personalNumber.message}</p>
      )}

      <InputGroups
        size="md"
        type={show ? "text" : "password"}
        placeholder="ُType Password..."
        icon={
          <i className="ki-duotone ki-lock-2">
            <i className="path1"></i>
            <i className="path2"></i>
            <i className="path3"></i>
            <i className="path4"></i>
            <i className="path5"></i>
          </i>
        }
        {...register("password")} // 传递register的所有属性
      >
        <InputLeftElement>
          <Button fontSize={10} onClick={showPasswordHandleClick}>
            {show ? "hide" : "show"}
          </Button>
        </InputLeftElement>
      </InputGroups>
      {/* 显示验证错误 */}
      {errors.password && (
        <p style={{ color: "red", margin: "0 0 10px 0" }}>{errors.password.message}</p>
      )}

      <Button
        className="login-btn"
        type="submit"
        mt={10}
        colorScheme="teal"
        size="lg"
      >
        login
      </Button>
    </form>
  );
};

export default Login;

关键说明

  • forwardRef的作用是将外部组件的ref传递给内部的Input元素,确保React Hook Form能正确获取输入框DOM节点
  • {...rest}用于传递register返回的name、onChange、onBlur等属性,这是React Hook Form跟踪表单状态的核心
  • 新增的错误提示可以让用户直观看到验证失败的原因

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 16:25:00