React Parent 组件计算 Child 组件的宽度和高度

React Parent component calculating width and height of Child Component

我有一个 Parent 组件在屏幕上重复通用 Child SVG 组件。

为了做到这一点,Parent 组件需要知道 child 的尺寸。

我曾经像这样将它们存储在 child 组件中(我知道这很不寻常但它有效)

function Child() {
    return <path id="child" />
} 
Child.width = 100
Child.height = 80

然后我曾经像这样在 parent 组件上阅读它们

function Parent(props) {
   let width = props.children.type.width
   let height = props.children.type.height
   return Array.from(Array(props.times), (e, i) => {
        return <Transform key={i} x={width*i} y={height*i}>
                     {props.children}
               </Transform> 
   })
}

我想要的是 Parent 容器自行计算 child 的尺寸,因此它们不是静态的。

我知道我需要使用这样的引用访问 child 的 dom

function Parent(props) {
       const test = React.useCallback(node => {
        if (node !== null) {
          const box = node.getBBox()
          console.log(box) //this works
          var width = box.width //this works too late
          var height = box.height
         }
       }, []);
       return Array.from(Array(props.times), (e, i) => {
            return <Transform key={i} x={width*i} y={height*i}>
                         <g ref={test}> {props.children}</g>
                   </Transform> 
       })
    }

但正如我想象的那样,React 不会等待我的回调来执行其余代码,所以它说宽度和高度未定义。

如何获得第一个元素的宽度和高度,然后让 Parent 组件完成他的工作?也许有悬念? 非常感谢任何帮助!

首先你可以通过url使用svg作为背景图片并放置背景重复和调整大小。但如果你想要这种方法,我们就去吧。 forwardRef/refs 有很多方法可以达到这种效果。下面的代码是第一个想到的 我建议您将 svg 作为 jsx/tsx file/react 组件 - 这样,否则您需要将 parentRef 提供给 layoutEffect dependancies

import React, { useLayoutEffect, useRef } from 'react';
import logo from './logo.svg';
import './App.css';
import Logo from './Logo';

const Parent1: React.FC = ({ children }) => {
    const parentRef = useRef<HTMLDivElement | null>(null);
    useLayoutEffect(() => {
        parentRef.current?.childNodes.forEach((node: any) =>
            console.log({ height: node?.clientHeight, width: node?.clientWidth }),
        );
    }, []);
    return (
        <div className='parent1' ref={parentRef}>
            {children}
        </div>
    );
};

function App() {
    return (
        <div className='App'>
            <Parent1>
                {Array(Math.ceil(Math.random() * 25 + 10))
                    /** 
                     If you will decide to go img way - you need to place 
                     parentRef as a dependancy for the layoutEffect
                     .fill(() => <img src={logo} alt='' />) 
    */
                    .fill(Logo)
                    .map((E, i) => {
                        return <E key={i} />;
                    })}
            </Parent1>
        </div>
    );
}

所以解决方案是更新 useEffect 中组件的状态,以便我们的视图在数据可用时得到更新:

function Parent(props) {
        const [height, setHeight] = React.useState()
        const [width, setWidth] = React.useState()
        const test = React.useCallback(node => {
        if (node !== null) {
          const box = node.getBBox()
          setWidth(box.width)
          setHeight(box.height)
         }
       }, []);
       return Array.from(Array(props.times), (e, i) => {
            return <Transform key={i} x={width*i} y={height*i}>
                         <g ref={test}> {props.children}</g>
                   </Transform> 
       })
    }