reactjsuse-ref

useRef for element in loop in react


Using React, i have a list of ref statically declared this way:

  let line1 = useRef(null);
  let line2 = useRef(null);
  let line3 = useRef(null);
  ...
  //IN MY RENDER PART
  <li ref={(el) => (line1 = el)}>line1</li>
  <li ref={(el) => (line2 = el)}>line1</li>
  <li ref={(el) => (line3 = el)}>line1</li>

the refs are then passed to an animation function and everything works correctly; now things changed a bit and i create the list item using map and im no longer able to ref the element correctly; i tried something like:

{menu.menu.map((D) => {
let newRef = createRef();
                    LiRefs.push(newRef);
                    return (
                      <li
                        key={D.id}
                        ref={(el) => (newRef = el)} >
                        {D.label}
                      </li>
                    );
                  })}

but the array i pass to the animation function is empty (i guess because the function is called inside useEffect hook and LiRefs is not yet a useRef) i also know the number of

  • i will create, so i can declare them at the beginning and the reference with something like

    ref={(el) => (`line${i}` = el)}
    

    which is not working any other solution i could try?


  • Solution

  • Issue

    This won't work as each render when menu is mapped it creates new react refs.

    Solution

    Use a ref to hold an array of generated refs, and assign them when mapping.

    const lineRefs = React.useRef([]);
    
    lineRefs.current = menu.menu.map((_, i) => lineRefs.current[i] ?? createRef());
    

    later when mapping UI, attach the react ref stored in lineRefs at index i

    {menu.menu.map((D, i) => {
      return (
        <li
          key={D.id}
          ref={lineRefs.current[i]} // <-- attach stored ref
          {D.label}
        </li>
      );
    })}