Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React hook form v7 Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()

Getting the error in browser Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()

enter image description here

My code:

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>
  )
}

And the Input comp:

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>
  )
}

I don't have this issue with ChakraUI that I've built but now just doing plain input as a separate component getting that issue.

I have tried some suggestions from here, but still can't fix it: https://github.com/react-hook-form/react-hook-form/issues/85

like image 374
Marius Avatar asked Jun 07 '21 19:06

Marius


People also ask

Is it possible to use forward refs in React React?

React see's a ref being passed, but you aren't using a forwardRef component. In addition to this, then you need to actually use the ref (and props) which you don't appear to be doing now in SelectCompanyField that are being provided by Controller

What is react-Hook-form?

A React form library that is both well thought out and flexible enough to get out of your way when you need it to. After fussing around with React forms for years, switching to react-hook-form feels like a superpower.

What are the main goals of react Hook form?

Reducing the amount of code you need to write, and removing unnecessary re-renders are some of the primary goals of React Hook Form. Now dive in and explore with the following example:

Can function components be given refs in React Redux?

Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef ()? atomiks/tippyjs-react#49 Warning: Function components cannot be given refs. Attempts to access this ref will fail. diegoddox/react-redux-toastr#220


3 Answers

You forgot to forward the ref in your InputFloatLabel. See https://reactjs.org/docs/forwarding-refs.html

In your case it would look like this:

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>
      )
    })
like image 181
Alwin07 Avatar answered Oct 16 '22 18:10

Alwin07


So the issue is that I think that the {...register("name"}} line actually includes a ref property. You could console.log that out to verify; this is what I found to be true when using {...field} with the ControlledComponent. A very quick fix to get rid of the console error is to just, after the line with the spread, to add a ref={null} to override this ref that is being passed in from the library.

like image 43
Joel M. Avatar answered Oct 16 '22 17:10

Joel M.


In https://react-hook-form.com/faqs, scroll to "How to share ref usage?" may help?

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>
  );
}
like image 3
Dang Tran Avatar answered Oct 16 '22 16:10

Dang Tran