首页 > 解决方案 > 如何从 ReactNode 获取元素的高度和宽度?

问题描述

我有一个动态组件,我在其中将孩子作为道具传递。所以道具看起来像:

interface Props {
   ...some props
   children: React.ReactNode
}

export default Layout({...some props, children}: Props) {...}

我需要访问组件中子元素的大小(高度和宽度)Layout请注意,孩子来自完全不同的组件并且是不相关的

我可以按如下方式使用 Layout 组件:

<Layout ...some props>
  <Child1 /> // I need to know the height and width of this child
  <Child2 /> // as well as this child
  <Child3 /> // and this child.
</Layout>

我怎样才能动态地做到这一点?我是否必须以某种方式转换ReactNodeHTMLDivElement?请注意,我无法将数组refs作为道具传递到Layout. 因为使用的页面Layout动态生成的。

因为很多人并不真正理解我所说的动态生成是什么意思。这意味着使用 Layout 组件的页面可以传入 x 个子级。孩子的数量是未知的,但永远不会是 0。

标签: javascriptreactjswebnext.js

解决方案


您可以通过React.Children在渲染子项之前动态构建引用列表来实现此目的。如果您有权访问子元素引用,则可以遵循以下方法。如果你不这样做,那么你可以按照底部的位。

您可以访问子元素引用

如果子组件传递它们的元素引用,您可以使用React.Children循环遍历每个子组件并获取每个元素引用。然后在渲染子组件之前使用它来执行计算。

即这是一个关于如何检索和使用引用的非常简单的示例。

interface LayoutWrapperProps {
  onMount: () => void;
}

const LayoutWrapper: React.FC<LayoutWrapperProps> = ({ onMount, children }) => {
  React.useEffect(() => {
    onMount();
  }, [onMount]);

  return <>{children}</>;
};

const Layout: React.FC = ({ children }) => {
  const references = React.useRef<HTMLElement[]>([]);

  React.useEffect(() => {
    references.current = [];
  });

  function getReference(ref: HTMLElement) {
    references.current = references.current.filter(Boolean).concat(ref);
  }

  function getHeights() {
    const heights = references.current.map((ref) =>
      ref?.getBoundingClientRect()
    );
    console.log(heights);
  }

  const clonedChildren = React.Children.map(children, (child) => {
    return React.cloneElement(child as any, {
      ref: getReference
    });
  });

  return <LayoutWrapper onMount={getHeights}>{clonedChildren}</LayoutWrapper>;
};

如果您无权访问子元素引用

如果子组件没有将元素作为引用传递,则必须将动态子组件包装在组件中,以便我们可以获得元素引用。IE

const WrappedComponent = React.forwardRef((props, ref) => {
   return (
     <div ref={ref}>
       {props.children}
     </div>
   )
});

渲染子组件时,上面获取引用的代码将起作用:

<Layout>
  <WrappedComponent>
    <Child1 />
  </WrappedComponent>
</Layout>

推荐阅读