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>
)
}
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"/>
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;
You have to use a separate set of hooks for each item, and this means you have to define a component for the items (or else you're using hooks inside a loop, which isn't allowed).
const Item = ({ text }) => {
const ref = useRef()
const [ height, setHeight ] = useState()
useLayoutEffect(() => {
setHeight( ref.current.getBoundingClientRect().height )
}, [])
return <div ref={ref}>{text}</div>
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.