Last updated: Apr 6, 2024
Reading timeยท2 min
The error "Function components cannot have string refs" occurs when we use a string as a ref in a function component.
To solve the error use the useRef()
hook to get a mutable ref object that
you can use as a ref inside of the component.
Here is an example of how the error occurs.
export default function App() { // A string ref has been found within a strict mode tree. // โ๏ธ Function components cannot have string refs. // We recommend using useRef() instead. return ( <div> <input type="text" id="message" ref="msg" /> </div> ); }
The issue in the code sample is that we are using a string as a ref.
useRef
hook to solve the errorTo solve the error, use the useRef hook to get a mutable ref object instead.
import {useEffect, useRef} from 'react'; export default function App() { const refContainer = useRef(null); useEffect(() => { // ๐๏ธ This is reference to input element console.log(refContainer.current); refContainer.current.focus(); }, []); return ( <div> <input type="text" id="message" ref={refContainer} /> </div> ); }
The useRef()
hook can be passed an initial value as an argument. The hook
returns a mutable ref object whose .current
property is initialized to the
passed argument.
current
property on the ref object to get access to the input
element on which we set the ref
prop.When we pass a ref prop to an element, e.g. <input ref={myRef} />
, React sets
the .current
property of the ref object to the corresponding DOM node.
useRef
hook creates a plain JavaScript object but gives you the same ref object on every render. In other words, it's pretty much a memoized object value with a .current
property.It should be noted that when you change the value of the current
property of
the ref, no re-renders are caused.
For example, a ref doesn't have to be included in the dependencies array of the
useEffect
hook because changing its current
property doesn't cause a
re-render.
import {useEffect, useRef} from 'react'; export default function App() { const refContainer = useRef(null); const refCounter = useRef(0); useEffect(() => { // ๐๏ธ This is reference to input element console.log(refContainer.current); refContainer.current.focus(); // ๐๏ธ Incrementing ref value does not cause re-render refCounter.current += 1; console.log(refCounter.current); }, []); return ( <div> <input type="text" id="message" ref={refContainer} /> </div> ); }
The useEffect
hook in the example is only run 2 times because useRef
doesn't
notify us when its content changes.
Changing the object's current
property does not cause a re-render.
If you try to access the ref's current
property before its corresponding DOM
element is rendered,
you'd get a null
or an undefined
value
back.
If you use TypeScript, you might get the error useRef "Object is possibly null"