Function components cannot be given refs. Attempts to access this ref will fail

avatar
Borislav Hadzhiev

Last updated: Apr 7, 2024
4 min

banner

# Function components cannot be given refs. Attempts to access this ref will fail

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().

function components cannot be given refs

shell
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.

App.js
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> ); };
The code for this article is available on GitHub

We can't set the ref prop on function components, such as Input.

Refs cannot be set on function components because they don't have instances (as opposed to class components and JSX elements).

However, we could rename the ref prop to something else, e.g. innerRef.

Here is the updated code that resolves the issue.

App.js
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> ); };

change ref prop name to resolve the issue

The code for this article is available on GitHub

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.

# Using the React.forwardRef() method to resolve the issue

You can also use the React.forwardRef() method to resolve the issue.

App.js
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> ); });

resolve the error using react forwardref

The code for this article is available on GitHub

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.

# Getting the error when using custom components

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:

App.js
<Link href="/login"> <NavLink style={{ cursor: "pointer" }}>Login</NavLink> </Link>

After:

App.js
<Link href="/login" passHref> <a> <NavLink style={{ cursor: "pointer" }}>Login</NavLink> </a> </Link>
The code for this article is available on GitHub

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:

App.js
<Link href='/'> <CustomImage /> </Link>

After:

App.js
<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.

# Setting the ref prop on a wrapper div element

An 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.

App.js
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>; }
The code for this article is available on GitHub

# A note on using TextField components from material UI

If you use the material UI library, note that you have to set the inputRef prop on TextField elements instead of ref.

App.js
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> ); }

set inputref prop on text field component

The code for this article is available on GitHub

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.

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.