Max SchmittMS
17th August 2021

React: Using Refs in Loops

Refs in React are a powerful tool and have become even more important with the introduction of stateful functional components that use hooks.

This slightly contrived example renders a button that focuses an input when it's clicked:

function MyComponent() {
const inputRef = useRef(null)
const onClickButton = () => {
inputRef.current.focus()
}
return (
<div>
<input ref={inputRef} />
<button onClick={onClickButton}>Focus input</button>
</div>
)
}

However, if you try to useRef() for a list of items, the rules of hooks will tell you that this is not allowed:

function MyComponent({ items }) {
return (
<div>
{items.map((item) => {
// ❌ ESLint:
// React Hook "useRef" cannot be called inside a
// callback. React Hooks must be called in a
// React function component or a custom React
// Hook function. (react-hooks/rules-of-hooks)
const ref = useRef()
return <input key={item.id} ref={ref} />
})}
</div>
)
}

A simple way around this is to create all the refs up-front and simply reference them in the loop:

function MyComponent({ items }) {
const refsById = useMemo(() => {
const refs = {}
items.forEach((item) => {
refs[item.id] = React.createRef(null)
})
return refs
}, [items])
return (
<div>
{items.map((item) => {
return <input key={item.id} ref={refsById[item.id]} />
})}
</div>
)
}

Notice that we're using React.createRef() to create the refs for each item (not the useRef hook!) By using the useMemo hook, we make sure to only recreate the refs if the items array changes.

Image of my head

About the author

Hi, I’m Max! I'm a fullstack JavaScript developer living in Berlin.

When I’m not working on one of my personal projects, writing blog posts or making YouTube videos, I help my clients bring their ideas to life as a freelance web developer.

If you need help on a project, please reach out and let's work together.

To stay updated with new blog posts, follow me on Twitter or subscribe to my RSS feed.