如何使用React hooks动态添加“refs”?

问题描述 投票:0回答:3

所以我有一个数据数组,并且我正在使用该数据生成一个组件列表。我想在每个生成的元素上有一个引用来计算高度。 我知道如何使用 Class 组件来做到这一点,但我想使用 React Hooks 来做到这一点。

这是一个解释我想要做什么的例子:

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>
  )
}
javascript reactjs react-hooks
3个回答
82
投票

不确定我完全理解你的意图,但我认为你想要这样的东西:

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"/>


0
投票

不需要有副作用的

useEffect
或其他脆弱的方法。根据官方指导,你可以使用“refcallbacks”

当需要设置 ref 时,React 将使用 DOM 节点调用您的 ref 回调,而当需要清除它时,将使用

null

 来调用您的 ref 回调。这使您可以维护自己的数组或 
Map
,并通过索引或某种 ID 访问任何引用。例如:

import { useRef } from "react"; const data = [{ id: 1, text: 'test1' },{ id: 2, text: 'test2' } ] const Component = () => { const itemsRef = useRef(new Map()); return ( <div> {data.map((item) => ( <div key={item.id} ref={el => el ? itemsRef.current.set(v.id, el) : itemsRef.current.delete(v.id)}> {item.text} </div> ))} </div> ); };
如果您的数组没有自然 ID,您始终可以回退到良好的 ol' 索引,但需要注意与在其他地方使用它作为键类似的警告。


-1
投票
您必须为每个项目使用一组单独的钩子,这意味着您必须为这些项目定义一个组件(否则您将在循环内使用钩子,这是不允许的)。

const Item = ({ text }) => { const ref = useRef() const [ height, setHeight ] = useState() useLayoutEffect(() => { setHeight( ref.current.getBoundingClientRect().height ) }, []) return <div ref={ref}>{text}</div> }
    
© www.soinside.com 2019 - 2024. All rights reserved.