[英]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.offsetHeight
和current.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:有两种情况:
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:代码中的一些话:
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
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
.请查看此处以了解useRef
和createRef
之间的区别。
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>
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. useWindowSize
和useSize
看起来非常相似,但是在查看源代码之后,第一个依赖于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
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
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 。
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.