-1

I have an array of react elements that I output using the map function:

{ elemsList.map((item, i) => { 
    return (
        <div 
           key={i}
           ref={refsArr[i]}
           data-grid={item.props["data-grid"]}
           onClick={e => doubleClickHandler(item.key, e)}
           style={{ 
                backgroundColor: i === selectedComponent ? '#828EE3' : "#102f6a", 
                color: "#fff", 
                height: "100%",
           }}
        >
            {item}
        </div>
    )}
) }

I need to create a ref for each of the elements of this array. I tried to do it using useRef passing an array there:

const refsArr = useRef([])
refsArr.current = elemsList.map((item, i) => refsArr.current[i] ?? setTimeout(createRef(), 5000))
...
{ elemsList.map((item, i) => { 
    return (
        <div 
           key={i}
           ref={refsArr[i]}
           data-grid={item.props["data-grid"]}
           onClick={e => doubleClickHandler(item.key, e)}
           style={{ 
                backgroundColor: i === selectedComponent ? '#828EE3' : "#102f6a", 
                color: "#fff", 
                height: "100%",
           }}
        >
            {item}
        </div>
    )}
) }

The problem is that when I try to output my ref array to the console, instead of a normal ref, I get an object with the following (or similar) content:

{ current: [53] }

How can I fix this problem?

Listopad02
  • 131
  • 1
  • 6

3 Answers3

0

you can use the combination of useRef and createRef.

const refsArr = useRef(elemsList.map(() => createRef()));
useEffect(() => {
  const classnames = refsArr.current.map(
    ref => ref.current.classname
  );
  console.log(classnames);
}, []);

//...
{ elemsList.map((item, i) => { 
    return (
        <div 
           key={i}
           ref={refsArr[i]}
           data-grid={item.props["data-grid"]}
           onClick={e => doubleClickHandler(item.key, e)}
           style={{ 
                backgroundColor: i === selectedComponent ? '#828EE3' : "#102f6a", 
                color: "#fff", 
                height: "100%",
           }}
        >
            {item}
        </div>
    )}
) }
DoctorHe
  • 65
  • 1
  • 9
0

This isn't going to work:

ref={refsArr[i]}

The ref prop expects a mutable ref object, or a ref callback.

refsArr[i] // undefined

Is going to return undefined, which is not a mutable ref object, or a ref callback.

Instead, pass a callback function that accepts the element and assigns it to the refsArr at the index.

ref={(element) => {
  refsArr.current[i] = element;
}}
Benjamin
  • 3,428
  • 1
  • 15
  • 25
0

You are using refsArr[i] as the ref attribute, but refsArr is a ref object itself, so you need to access its current property first. You should use refsArr.current[i] instead.

And you are not updating your refsArr when your elemsList changes, which may cause stale or missing refs. You should use useEffect to sync your refsArr with your elemsList.

You can use useEffect and a callback ref to create and update your refsArr dynamically. For example:

const App = ({ elemsList }) => {
  const refsArr = useRef([]);

  useEffect(() => {
    refsArr.current = refsArr.current.slice(0, elemsList.length);
  }, [elemsList]);

  return (
    <>
      {elemsList.map((item, i) => {
        return (
          <div
            key={i}
            ref={(el) => (refsArr.current[i] = el)}
            data-grid={item.props["data-grid"]}
            onClick={(e) => doubleClickHandler(item.key, e)}
            style={{
              backgroundColor: i === selectedComponent ? "#828EE3" : "#102f6a",
              color: "#fff",
              height: "100%",
            }}
          >
            {item}
          </div>
        );
      })}
    </>
  );
};
Pluto
  • 4,177
  • 1
  • 3
  • 25