Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add "refs" dynamically with react hooks?

So I have an array of data in and I am generating a list of components with that data. I'd like to have a ref on each generated element to calculate the height. I know how to do it with a Class component, but I would like to do it with React Hooks.

Here is an example explaining what I want to do:

import React, {useState, useCallback} from 'react' const data = [   {     text: 'test1'   },   {     text: 'test2'   } ] const Component = () => {   const [height, setHeight] = useState(0);   const measuredRef = useCallback(node => {     if (node !== null) {       setHeight(node.getBoundingClientRect().height);     }   }, []);    return (     <div>       {         data.map((item, index) =>            <div ref={measuredRef} key={index}>             {item.text}           </div>         )       }     </div>   ) } 
like image 657
Constantin Chirila Avatar asked May 05 '19 19:05

Constantin Chirila


People also ask

How do you add ref in React hook?

A ref can be created in two ways- by the useRef hook or by the createRef function. useRef: The useRef is a hook that uses the same ref throughout. It saves its value between re-renders in a functional component and doesn't create a new instance of the ref for every re-render.

How do I create a dynamic REF IN React native?

There are two ways to create refs in React the first is by using React. createRef() method or the useRef() hook. In this article, we will be using the hook. First, we import the useRef hook and use it to create a ref, passing null to it as an argument.

How do you add refs to a React element?

Creating RefsRefs are created using React. createRef() and attached to React elements via the ref attribute. Refs are commonly assigned to an instance property when a component is constructed so they can be referenced throughout the component.

Can I use REF in useEffect?

So the reason you shouldn't list a ref in your useEffect dependency array is because it's an indication that you want the effect callback to re-run when a value is changed, but you're not notifying React when that change happens.


2 Answers

Not sure i fully understand your intent, but i think you want something like this:

const {    useState,    useRef,    createRef,    useEffect  } = React;    const data = [    {      text: "test1"    },    {      text: "test2"    }  ];    const Component = () => {    const [heights, setHeights] = useState([]);    const elementsRef = useRef(data.map(() => createRef()));      useEffect(() => {      const nextHeights = elementsRef.current.map(        ref => ref.current.getBoundingClientRect().height      );      setHeights(nextHeights);    }, []);      return (      <div>        {data.map((item, index) => (          <div ref={elementsRef.current[index]} key={index} className={`item item-${index}`}>            {`${item.text} - height(${heights[index]})`}          </div>        ))}      </div>    );  };    const rootElement = document.getElementById("root");  ReactDOM.render(<Component />, rootElement);
.item {    box-sizing: border-box;    display: flex;    align-items: center;    justify-content: center;    border: 1px solid #ccc;  }    .item-0 {    height: 25px;  }    .item-1 {    height: 50px;  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>  <div id="root"/>
like image 122
Sagiv b.g Avatar answered Sep 19 '22 02:09

Sagiv b.g


I created a tiny npm package that exposes a React Hook to handle setting and getting refs dynamically as I often run into the same problem.

npm i use-dynamic-refs 

Here's a simple example.

import React, { useEffect } from 'react'; import useDynamicRefs from 'use-dynamic-refs';  const Example = () =>  {   const foo = ['random_id_1', 'random_id_2'];   const [getRef, setRef] =  useDynamicRefs();    useEffect(() => {     // Get ref for specific ID      const id = getRef('random_id_1');     console.log(id)   }, [])      return (        <>         {/* Simple set ref. */}         <span ref={setRef('random_id_3')}></span>           {/*  Set refs dynamically in Array.map() */}         { foo.map( eachId => (           <div key={eachId} ref={setRef(eachId)}>Hello {eachId}</div>))}       </>     ) }  export default Example; 
like image 27
fitzmode Avatar answered Sep 22 '22 02:09

fitzmode