简体   繁体   English

如何使用 Hooks 在 React 中获取父级宽度/高度?

[英]How to get parent width/height in React using Hooks?

I'm creating a component and I need to get it's parent <div> width and height.我正在创建一个组件,我需要获取它的父<div>宽度和高度。 I'm using Hooks, so all my components are functions.我正在使用 Hooks,所以我所有的组件都是函数。 I've read some examples using classes, but this won't apply to my component.我已经阅读了一些使用类的示例,但这不适用于我的组件。

So I have this component:所以我有这个组件:

export default function PlantationMap(props) {
    <div className="stage-canvas">
        <Stage
          width={window.innerWidth * 0.5}
          height={window.innerHeight * 0.5}
          onWheel={handleWheel}
          scaleX={stage.stageScale}
          scaleY={stage.stageScale}
          x={stage.stageX}
          y={stage.stageY}
          draggable
        / >
    </div>
}

How could I get the <div> height and width to use in <Stage width={} height={} /> ?如何获得<div>高度和宽度以在<Stage width={} height={} />中使用?

Thank you very much in advance非常感谢您提前

Edit: I tried using the useRef() hook, like this:编辑:我尝试使用useRef()钩子,如下所示:

const div = useRef();

return (
  <div ref={div}>
  ...
  </div>
)

But I can't access the div.current object但我无法访问div.current object

I think useCallback is what you want to use so you can get the width and height when it changes.我认为 useCallback 是你想要使用的,所以当它改变时你可以得到宽度和高度。

  const [height, setHeight] = useState(null);
  const [width, setWidth] = useState(null);
  const div = useCallback(node => {
    if (node !== null) {
      setHeight(node.getBoundingClientRect().height);
      setWidth(node.getBoundingClientRect().width);
    }
  }, []);

  return (
    <div ref={div}>
    ...
    </div>
  )

Declare a reference using useRef hook and then read current.offsetHeight and current.offsetWidth properties.使用useRef挂钩声明引用,然后读取current.offsetHeightcurrent.offsetWidth属性。

Here is the code:这是代码:

import React, { useEffect, useRef } from 'react';

const PlantationMap = (props) => {

    const stageCanvasRef = useRef(null);

    // useEffect will run on stageCanvasRef value assignment
    useEffect( () => {

        // The 'current' property contains info of the reference:
        // align, title, ... , width, height, etc.
        if(stageCanvasRef.current){

            let height = stageCanvasRef.current.offsetHeight;
            let width  = stageCanvasRef.current.offsetWidth;
        }

    }, [stageCanvasRef]);

    return(
        <div className = "stage-canvas" ref = {stageCanvasRef}>
            <Stage
              width={window.innerWidth * 0.5}
              height={window.innerHeight * 0.5}
              onWheel={handleWheel}
              scaleX={stage.stageScale}
              scaleY={stage.stageScale}
              x={stage.stageX}
              y={stage.stageY}
              draggable
            / >
        </div>);

}

export default PlantationMap;

to my knowledge if it is concerned with style can only be registered by:据我所知,如果它与风格有关,只能通过以下方式注册:

<Stage style={{width:window.innerWidth * 0.5,height:width:window.innerWidth * 0.5}} />

You can make use of the built-inResizeObserver :您可以使用内置的ResizeObserver

export default function PlantationMap(props) {
    const [width, setWidth] = useState(100);
    const [height, setHeight] = useState(100);

    useEffect(() => {
        const resizeObserver = new ResizeObserver((event) => {
            // Depending on the layout, you may need to swap inlineSize with blockSize
            // https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentBoxSize
            setWidth(event[0].contentBoxSize[0].inlineSize);
            setHeight(event[0].contentBoxSize[0].blockSize);
        });

        resizeObserver.observe(document.getElementById("div1"));
    });

    return (
        <div id="div1" className="stage-canvas">
            <Stage
                width={width * 0.5}
                height={height * 0.5}
                onWheel={handleWheel}
                scaleX={stage.stageScale}
                scaleY={stage.stageScale}
                x={stage.stageX}
                y={stage.stageY}
                draggable
            / >
        </div>
    );
}

I think ResizeObserver is the way to go as mentioned in the answer from Dan.我认为 ResizeObserver 是 go 的方式,如 Dan 的回答中所述。 I just wouldn't use the document.getElementById .我只是不会使用document.getElementById Either use useMeasure from react-use or create everything on your own.要么使用react- use 中的useMeasure ,要么自己创建所有内容。

There are two scenarios:有两种情况:

  1. Component contains the container that you'd like to observe组件包含您要观察的容器
  2. Component is a child component and doesn't have the container reference组件是子组件,没有容器引用

To 1 - Reference directly accessible To 1 - 可直接访问的引用

In this case, you can create the reference with useRef in the component and use it at resizeObserver.observe(demoRef.current) .在这种情况下,您可以在组件中使用useRef创建引用,并在resizeObserver.observe(demoRef.current)中使用它。

import "./styles.css";
import React, { useEffect, useRef, useState } from "react";

const DisplaySize = ({ width, height }) => (
  <div className="centered">
    <h1>
      {width.toFixed(0)}x{height.toFixed(0)}
    </h1>
  </div>
);

const Demo = () => {
  const [width, setWidth] = useState(100);
  const [height, setHeight] = useState(100);
  const demoRef = useRef();

  useEffect(() => {
    const resizeObserver = new ResizeObserver((event) => {
      // Depending on the layout, you may need to swap inlineSize with blockSize
      // https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentBoxSize
      setWidth(event[0].contentBoxSize[0].inlineSize);
      setHeight(event[0].contentBoxSize[0].blockSize);
    });

    if (demoRef) {
      resizeObserver.observe(demoRef.current);
    }
  }, [demoRef]);

  return (
    <div ref={demoRef} className="App">
      <DisplaySize width={width} height={height} />
    </div>
  );
}; //);

export default function App() {
  return <Demo />;
}

To 2 - Reference of container not directly accessible: To 2 - 无法直接访问容器的引用:

This case is probably happening more often and requires slightly more code.这种情况可能发生得更频繁,并且需要更多的代码。 You need to pass the reference from the parent to the child component with React.forwardRef .您需要使用React.forwardRef将父组件的引用传递给子组件。

Demo code can be found below or in the following Codesandbox演示代码可以在下面或下面的Codesandbox中找到

Some words to the code:代码中的一些话:

  • In the parent component you create a reference with const containerRef = useRef() and use it at the main container with <div ref={containerRef}/> .在父组件中,您使用const containerRef = useRef()创建一个引用,并通过<div ref={containerRef}/>在主容器中使用它。 Under the hood it will do something like ref => containerRef.current=ref在引擎盖下它会做类似ref => containerRef.current=ref
  • Next, pass the reference to the Demo component.接下来,将引用传递给Demo组件。

Why not use React.createRef ?为什么不使用React.createRef

That would work too but it would recreate the reference on every render of your App.这也可以,但它会在您的应用程序的每个渲染上重新创建引用。 Please have a look here for an explanation of the difference between useRef and createRef .请查看此处以了解useRefcreateRef之间的区别。

In short, use useRef with functional components and use createRef with class-based components.简而言之,将useRef与功能组件一起使用,将createRef与基于类的组件一起使用。

 const {useEffect, useRef, useState} = React; const DisplaySize = ({ width, height }) => ( <div className="centered"> <h1> {width.toFixed(0)}x{height.toFixed(0)} </h1> </div> ); const Demo = React.forwardRef((props, ref) => { const [width, setWidth] = useState(100); const [height, setHeight] = useState(100); useEffect(() => { const resizeObserver = new ResizeObserver((event) => { // Depending on the layout, you may need to swap inlineSize with blockSize // https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentBoxSize setWidth(event[0].contentBoxSize[0].inlineSize); setHeight(event[0].contentBoxSize[0].blockSize); }); if (ref && ref.current) { resizeObserver.observe(ref.current); } }, [ref]); return <DisplaySize width={width} height={height} />; }); function App() { const containerRef = useRef(); return ( <div ref={containerRef} className="App"> <Demo ref={containerRef} /> </div> ); } const rootElement = document.getElementById("root"); ReactDOM.render( <App />, rootElement );
 /* apply a natural box layout model to all elements, but allowing components to change */ html { box-sizing: border-box; } *, *:before, *:after { box-sizing: inherit; } html, body { margin: 0; padding: 0; }.App { position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; font-family: sans-serif; text-align: center; border: 4px solid red; }.centered { display: flex; /* establish flex container */ flex-direction: column; /* make main axis vertical */ justify-content: center; /* center items vertically, in this case */ align-items: center; /* center items horizontally, in this case */ height: 100%; }
 <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <div id="root"></div>

Library React-use库反应使用

There are also some useful hooks in React-use that could help here. React-use中还有一些有用的钩子可以在这里提供帮助。

useWindowSize and useSize look pretty similar but after looking at the source code the first one relies on the window.onresize event and requires less code to implement. useWindowSizeuseSize看起来非常相似,但是在查看源代码之后,第一个依赖于window.onresize事件并且需要更少的代码来实现。

useSize will add an iframe below the current component ( z-index: -1 ) to track the size with resize event and requires more code. useSize将在当前组件( z-index: -1 )下方添加一个 iframe 以使用resize事件跟踪大小,并且需要更多代码。 It also adds a little debounce with setTimeout .它还使用setTimeout增加了一点去抖动。

So use useWindowSize if you just need the width/height to do some calculations on the first render and useSize if you'd like to show that the size changed.因此,如果您只需要宽度/高度来对第一次渲染进行一些计算,请使用useSize useWindowSize

useWindowSize使用窗口大小

If you just need to get the window size useWindowSize is the way to go.如果您只需要获取 window 大小,则使用WindowSize 是go的方式。 They're doing it with onresize event with document.addEventlistener('resize', resizeHandler) and checking innerWidth / innerHeight Codesandbox Demo他们正在使用document.addEventlistener('resize', resizeHandler)使用onresize 事件并检查innerWidth / innerHeight Codesandbox Demo

useMeasure使用测量

To track an element size, useMeasure can be used.要跟踪元素大小,可以使用useMeasure It is using ResizeObserver under the hood, so it's like the code above where ref is the reference you'd like to track:它在后台使用ResizeObserver ,因此就像上面的代码一样,其中ref是您要跟踪的引用:

The first element returned by useMeasure is the setRef method. useMeasure返回的第一个元素是setRef方法。 So you can do the following in your component:因此,您可以在组件中执行以下操作:

const [setRef, { width, height }] = useMeasure();
useEffect(() => {
    setRef(ref.current)
}, [])

Please have a look at the following Codesandbox .请看下面的Codesandbox

useSize使用尺寸

If you want to track the size of a component useSize could be used as mentioned in the docs .如果您想跟踪组件的大小useSize可以按照文档中的说明使用。 Codesandbox Demo useSize useSize Demo 使用大小

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 有没有其他简单的方法可以使用 React Hooks 获取容器的高度和宽度? - Is there any other easy way to get the height and width of a container using React Hooks? 如何使用本机反应在样式表文件中获取 window 宽度和高度? - How to get the window width and height in stylesheet file using react native? 如何使用react-native获取父块高度? - How to get parent block height using react-native? Reactjs - 使用 React Hooks 获取 div/图像的高度 - Reactjs - Get Height of a div/image using React Hooks 如果他们的孩子使用javascript不同,如何分别获得所有父div高度和宽度 - How to get all parent div height and width separately if their childs are different using javascript 如何使用JavaScript将SVG缩放到父容器的全部高度和宽度? - How to get SVG to scale to full height and width of parent container using JavaScript? 如何获取父元素的最小高度/宽度并通过 CSS 设置为子元素的高度/宽度 - How to get min height/width of parent element and set to it's child height/width by CSS 使用 React Hooks 自动调整 iframe 的高度 - Automatically adjust height of iframe using React Hooks 如何使用父divs属性设置画布的宽度/高度 - How to set canvas width / height using parent divs attributes 如何在不调用 window 的情况下在 React 中获取设备宽度/高度 object - How to get device width/height in React without calling the window object
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM