Last updated: Apr 7, 2024
Reading time·4 min
The React warning "Function components cannot be given refs. Attempts to
access this ref will fail. Did you mean to use React.forwardRef()?" occurs when
you pass the ref
prop to a function component.
To resolve the issue, pass a prop of a different name to the component, e.g.
inputRef
or use React.forwardRef()
.
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Here is an example of how the warning occurs.
import React, {useRef} from 'react'; export default function App() { const inputRef = useRef(null); return ( <div> <h2>bobbyhadz.com</h2> <Input ref={inputRef} /> </div> ); } // ⛔️ Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()? const Input = ({ref}) => { return ( <div> <input id="message" name="message" ref={ref} /> </div> ); };
We can't set the ref
prop on function components, such as Input
.
However, we could rename the ref
prop to something else, e.g. innerRef
.
Here is the updated code that resolves the issue.
import React, {useRef} from 'react'; export default function App() { const inputRef = useRef(null); return ( <div> <h2>bobbyhadz.com</h2> <Input innerRef={inputRef} /> </div> ); } const Input = ({innerRef}) => { const logInputValue = () => { console.log(innerRef.current.value); }; return ( <div> <input id="message" name="message" ref={innerRef} /> <button onClick={logInputValue}>Log value</button> </div> ); };
We are no longer passing a ref
prop to the Input
component.
Instead, we passed an innerRef
prop to the component and set the ref
prop
on the input
element.
The ref
prop can only be set on JSX elements, such as input
, textarea
,
etc.
The prop cannot be set on function components, such as Input
(capital I
).
The easiest way to get around this is to simply pass a prop of a different name as shown in the code sample.
Note that the name of the prop doesn't have to be innerRef
, you could use any
other value as long as you don't use the ref
prop name.
React.forwardRef()
method to resolve the issueYou can also use the React.forwardRef() method to resolve the issue.
import React, {useRef, forwardRef} from 'react'; export default function App() { const inputRef = useRef(null); return ( <div> <h2>bobbyhadz.com</h2> <Input ref={inputRef} /> </div> ); } const Input = forwardRef((props, ref) => { const logInputValue = () => { console.log(ref.current.value); }; return ( <div> <input id="message" name="message" ref={ref} /> <button onClick={logInputValue}>Log value</button> </div> ); });
Ref forwarding enables components to take a ref and pass it further down (forward it) to a child.
Notice that we passed the ref
prop to the Input
component (and not
innerRef
).
The Input
component uses the forwardRef
method to get the ref
that was
passed to it and sets the ref
prop on an input
element.
React automatically passes the ref
to the (props, ref) => {}
function
inside forwardRef
as the second argument.
When the ref
prop is set on the input
element, the ref.current
property
refers to the input
element.
Note that the second ref
argument is only passed when you define a component
with React.forwardRef
.
Regular React function components only get passed a props
object argument.
You might also get the error when using custom components from third-party libraries.
If you got the error when using the Link
component in Next.js with another
custom component, try to wrap the custom component in an <a>
tag.
Before:
<Link href="/login"> <NavLink style={{ cursor: "pointer" }}>Login</NavLink> </Link>
After:
<Link href="/login" passHref> <a> <NavLink style={{ cursor: "pointer" }}>Login</NavLink> </a> </Link>
I simply wrapped the NavLink
with an a
element and set the passHref
prop.
This way, the ref
will get passed to the <a>
HTML element and not the
NavLink
function component.
This works in a similar way when using other custom components - wrap the
component that causes the issue with a div
tag.
Before:
<Link href='/'> <CustomImage /> </Link>
After:
<Link href='/'> <div> <CustomImage /> </div> </Link>
I simply wrapped the CustomImage
component with a div
tag so the ref
prop
gets passed to the div
and not to the function component.
ref
prop on a wrapper div
elementAn alternative solution that might or might not work depending on your use case
is to wrap the function component with a div
and set the ref
prop on the
wrapper div
element.
import React, {useRef} from 'react'; export default function App() { const inputRef = useRef(null); return ( <div> <h2>bobbyhadz.com</h2> <div ref={inputRef}> <Button>Click</Button> </div> </div> ); } function Button({children}) { return <button>{children}</button>; }
TextField
components from material UIIf you use the material UI library, note
that you have to set the inputRef
prop on TextField
elements instead of
ref
.
import React, {useRef} from 'react'; import TextField from '@mui/material/TextField'; export default function App() { const inputRef = useRef(null); const logInputValue = () => { console.log(inputRef.current); console.dir(inputRef.current.value); }; return ( <div> <h2>bobbyhadz.com</h2> <TextField inputRef={inputRef} id="outlined-basic" label="Outlined" variant="outlined" defaultValue="" /> <button onClick={logInputValue}>Click</button> </div> ); }
Notice that we set the inputRef
prop on the TextField
component and not the
ref
prop.
This is the case because the TextField
component contains many nested DOM
elements and setting the ref
prop on the outermost element is not what we
need.