'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()
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
Solution 1:[1]
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.
Solution 2:[2]
You forgot to forward the ref in your InputFloatLabel. See https://reactjs.org/docs/forwarding-refs.html
You you 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>
)
})
Solution 3:[3]
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>
);
}
Solution 4:[4]
the field element and register function pass a ref to the element. If you define a custom React Component and try to use it within a controller or with register, funky things can happen. I found using React.forwardRef() solves the problem when using Custom Components.
CustomSwitchComponent.tsx
import React from 'react';
import {FormControlLabel, Switch, SxProps, Theme} from "@mui/material";
const TradingStrategyEditFormInstructionsInputSwitch:
// Note this type allows us to do React.forwardRef(Component)
React.ForwardRefRenderFunction<HTMLButtonElement, {
label: string,
checked: boolean,
onBlur: React.FocusEventHandler<HTMLButtonElement>
}> = ({label, ...rest}) => {
// Spreading ...rest here will pass the ref :)
return <FormControlLabel control={<Switch {...rest} />}
labelPlacement={"top"}
label={label}
/>;
};
// *Huzzah!*
export default React.forwardRef(TradingStrategyEditFormInstructionsInputSwitch);
CustomSwitchController.tsx
<Controller
control={formCtx.control}
name={fieldPath}
key={type + side + key}
render={({field}) => {
return <TradingStrategyEditFormInstructionsInputField
{...field}
label={key}
checked={field.value}
onBlur={() => {
field.onBlur()
handleOnBlur(key)
}}
/>
}}/>
Idk if we're allowed to link YT Videos, but techsith has a great video on using forwardRef with useRef that should clear things up. https://www.youtube.com/watch?v=ScT4ElKd6eo
Solution 5:[5]
Your input component does not export ref as props since it is a functional component.
React.useEffect(() => {
register('name', { required: true });
}, []);
<InputFloatLabel
type="text"
placeholder="Name"
name="name"
// Remove the register from here
/>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Joel M. |
| Solution 2 | |
| Solution 3 | Dang Tran |
| Solution 4 | |
| Solution 5 | Monish N |

