如何使用react-hooks动态添加“参考”?

IT技术 javascript reactjs react-hooks
2021-03-04 22:21:10

所以我有一个数据数组,我正在用这些数据生成一个组件列表。我想在每个生成的元素上都有一个 ref 来计算高度。我知道如何用 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>
  )
}
3个回答

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

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

如果你使用钩子,你应该使用 useRef 而不是 createRef。
2021-04-25 22:21:10
这或多或少是我需要的。谢谢!
2021-04-28 22:21:10
@akshay您可以使用地图对象而不是数组
2021-04-29 22:21:10
@giorgim 如果数据是动态的,则将其放入状态
2021-05-09 22:21:10
如果数据是动态变化的(添加、删除),则不起作用
2021-05-13 22:21:10

我创建了一个npm小包,它公开了一个React Hook来处理设置和动态获取 refs,因为我经常遇到同样的问题。

npm i use-dynamic-refs

这是一个简单的例子。

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;
你救我。谢谢!
2021-05-01 22:21:10
干得好。UPVOTED。
2021-05-04 22:21:10
它让我返回空。每当我尝试做 getRef
2021-05-07 22:21:10

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

const Item = ({ text }) => {
    const ref = useRef()
    const [ height, setHeight ] = useState()
    useLayoutEffect(() => {
        setHeight( ref.current.getBoundingClientRect().height )
    }, [])
    return <div ref={ref}>{text}</div>
}
我认为可能有一种我看不到的方式......我对钩子很陌生。我想我将不得不使用类组件!谢谢你的回答!
2021-04-28 22:21:10
对不起,如果不清楚,你可以用钩子来做,只是<Item>在里面渲染data.map
2021-05-09 22:21:10