如何在 React js 的功能组件中创建 ref?

how to create ref in functional component in react js?

我正在尝试在功能组件中创建 ref。但得到的输出与 class based component 相比有所不同。

这里很简单 class based component。在基于 class 的组件中,我得到了正确的引用

这里是基于class的组件 https://stackblitz.com/edit/react-vh86ou?file=src%2Ftabs.js

查看参考映射 (正确的参考映射)

我正在尝试对功能组件执行相同的映射但得到不同的输出,为什么?

这是我的功能组件 https://stackblitz.com/edit/react-nagea2?file=src%2FApp.js

export default function App() {
  useEffect(() => {
    console.log('---', tabRefs);
  }, []);
  const getTabProps = ({ title, key, selected, tabIndex }) => ({
    selected,
    children: title,
    key: tabPrefix + key,
    id: tabPrefix + key,
    ref: e => (tabRefs[tabPrefix + key] = e),
    originalKey: key
  });

我得到这个输出

为什么我从 HTMLLIELEMENT 而不是 TAB 组件获取 Ref?

更新 :

我正在尝试获取 offsetWidth 仍然无法获取 https://stackblitz.com/edit/react-nagea2?file=src%2FApp.js

useEffect(() => {
    console.log('---', tabRefs);

    Object.keys(tabRefs).forEach(key => {
      console.log(key);
      if (tabRefs[key]) {
        const width = tabRefs[key].tab.offsetWidth;
        console.log(width);
      }
    });
  }, []);

您不能将 ref 属性添加到功能组件,原因如前所述here。 您可以使用 forwardRef 函数结合 useImperativeHandle 钩子来模拟 class 组件 ref,但是只要 Tab 是一个函数组件,您就不能将 ref 添加到您的 Tab 组件。

例如,您可以向 Tab 组件添加一些代码,如下所示。

const Tab = React.forwardRef(({ children }, ref) => {
  const liRef = useRef(null);
  React.useImperativeHandle(ref, () => ({
    tab: liRef.current
  }));
  return <li ref={liRef}>{children}</li>;
});
export default Tab;

如果你想存储所有Tab组件的所有refs并在以后调用它的一些函数,你可以在useImperativeHandle hook中添加函数。

正如@TabW 所解释的,函数组件没有引用。但是 您不需要对 Tab 组件本身的引用 。您只需转发 ref 即可获得底层 li 元素的 offsetWidth,而无需使用 useImperativeHandle.

将您转发的参考直接附加到 li:

const Tab = React.forwardRef(({ children }, ref) => {
  return <li ref={ref}>{children}</li>;
});

并从您访问它的地方删除 .tab 属性。