React hook form v7 Function 组件不能被赋予引用。尝试访问此引用将失败。你的意思是使用 React.forwardRef()

IT技术 reactjs typescript ref
2021-05-14 10:42:48

在浏览器中获取错误 Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()

在此处输入图片说明

我的代码:

import { yupResolver } from '@hookform/resolvers/yup'
import { useState } from 'react'
import { SubmitHandler, useForm } from 'react-hook-form'
import { contactSchema } from 'schemas/schemas'
import { InputFloatLabel } from './components/Inputs/InputFloatLabel'

type TypeFormInput = {
  name: string
  email: string
  textarea: string
}

export const Register = () => {
  const [isLoading, setIsLoading] = useState(false)

  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<TypeFormInput>({ resolver: yupResolver(contactSchema) })

  const onSubmit: SubmitHandler<TypeFormInput> = async ({ name, email }) => {
    console.log('🚀 ~ file: Register.tsx ~ line 25 ~ email', email)
    console.log('🚀 ~ file: Register.tsx ~ line 25 ~ name', name)
  }


  return (
    <div>
      <form onSubmit={handleSubmit(onSubmit)}>
        <div>
          <InputFloatLabel
            type="text"
            placeholder="Name"
            {...register('name')}
          />

          <button type="submit">{isLoading ? 'Loading' : 'Send Mail'}</button>
        </div>
      </form>
    </div>
  )
}

和输入组合:

import { useState } from 'react'

type typeInput = {
  placeholder: string
  type?: string
}

export const InputFloatLabel: React.FC<typeInput> = ({ type, placeholder, ...props }) => {
  const [isActive, setIsActive] = useState(false)

  const handleTextChange = (text: string) => {
    if (text !== '') setIsActive(true)
    else setIsActive(false)
  }

  return (
    <div>
      <input
        {...props}
        id={placeholder}
        type={placeholder ? placeholder : 'text'}
        onChange={(e) => handleTextChange(e.target.value)}
      />
      <label htmlFor={placeholder}>
        {placeholder ? placeholder : 'Placeholder'}
      </label>
    </div>
  )
}

我构建的 ChakraUI 没有这个问题,但现在只是将普通输入作为一个单独的组件来解决这个问题。

我从这里尝试了一些建议,但仍然无法解决:https : //github.com/react-hook-form/react-hook-form/issues/85

4个回答

所以问题是我认为该{...register("name"}}行实际上包含一个 ref 属性。您可以通过 console.log 将其注销以进行验证;这是我在使用{...field}ControlledComponent时发现的事实摆脱控制台错误的一个非常快速的解决方法是在带有扩展的行之后添加一个ref={null}来覆盖从库中传入的这个引用。

您忘记转发 InputFloatLabel 中的 ref。https://reactjs.org/docs/forwarding-refs.html

你的情况它看起来像这样:

export const InputFloatLabel: React.FC<typeInput> =
    // Use React.forwardRef
    React.forwardRef(({type, placeholder, ...props}, ref) => {
      const [isActive, setIsActive] = useState(false)

      const handleTextChange = (text: string) => {
        if (text !== '') setIsActive(true)
        else setIsActive(false)
      }

      return (
        <div>
          <input
            ref={ref /* Pass ref */}
            {...props}
            id={placeholder}
            type={placeholder ? placeholder : 'text'}
            onChange={(e) => handleTextChange(e.target.value)}
          />
          <label htmlFor={placeholder}>
            {placeholder ? placeholder : 'Placeholder'}
          </label>
        </div>
      )
    })

https://react-hook-form.com/faqs 中,滚动到“如何共享 ref 用法?” 可能有帮助吗?

import React, { useRef } from "react";
import { useForm } from "react-hook-form";

export default function App() {
  const { register, handleSubmit } = useForm();
  const firstNameRef = useRef(null);
  const onSubmit = data => console.log(data);
  const { ref, ...rest } = register('firstName');

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...rest} name="firstName" ref={(e) => {
        ref(e)
        firstNameRef.current = e // you can still assign to ref
      }} />

      <button>Submit</button>
    </form>
  );
}

您的输入组件不会将 ref 导出为 props,因为它是一个功能组件。

 React.useEffect(() => {
    register('name', { required: true });
  }, []);

         <InputFloatLabel
            type="text"
            placeholder="Name"
            name="name"
           // Remove the register from here
          />