A very common used pattern in react development is the mapping of data. Given the following array:
const arr = [1, 2, 3]
We can easily turn them into valid JSX components:
arr.map((item, index) => {
<div key={index}>{item}</div>
})
There are several reason why you might want to retain a ref to every of the mapped elements. For instance to use the quite handy scrollIntoView()
function that react provides.
To collect our refs on the fly (and hold on to them between renders) we first have to create an useRef with an empty array:
const refs = useRef([])
//refs = {current: []}
We now can update our mapping function to add references to refs
(or shall I say refs-store? 🤔):
arr.map((item, index) => {
<div key={index}
ref={(element) => {refs.current[index] = element}}
//Adds the current element to our refs.current array
>{item}</div>
})
The ref property on our JSX-div can take a function where the current element is passed in as the first argument.
Our refs store now looks like this:
const refs = {current: [<div>1</div>, <div>2</div>, <div>3</div>]
The single elements can be targeted with the usual syntax:
refs.current[0] //<div>1</div>
//We can call scrollIntoView like this:
refs.current[2].scrollIntoView();
Full code
import React, { useRef } from "react";
export default function App() {
const arr = [1, 2, 3];
const refs = useRef([]);
return (
<div className="App">
{arr.map((item, index) => {
return (
<div
key={index}
ref={(element) => {
refs.current[index] = element;
}}
>
{item}
</div>
);
})}
</div>
);
}