![](/img/trans.png)
[英]Is there any other easy way to get the height and width of a container using React Hooks?
[英]How to get parent width/height in React using Hooks?
我正在创建一个组件,我需要获取它的父<div>
宽度和高度。 我正在使用 Hooks,所以我所有的组件都是函数。 我已经阅读了一些使用类的示例,但这不适用于我的组件。
所以我有这个组件:
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>
}
如何获得<div>
高度和宽度以在<Stage width={} height={} />
中使用?
非常感谢您提前
编辑:我尝试使用useRef()
钩子,如下所示:
const div = useRef();
return (
<div ref={div}>
...
</div>
)
但我无法访问div.current
object
我认为 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>
)
使用useRef
挂钩声明引用,然后读取current.offsetHeight
和current.offsetWidth
属性。
这是代码:
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;
据我所知,如果它与风格有关,只能通过以下方式注册:
<Stage style={{width:window.innerWidth * 0.5,height:width:window.innerWidth * 0.5}} />
您可以使用内置的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>
);
}
我认为 ResizeObserver 是 go 的方式,如 Dan 的回答中所述。 我只是不会使用document.getElementById
。 要么使用react- use 中的useMeasure
,要么自己创建所有内容。
有两种情况:
To 1 - 可直接访问的引用
在这种情况下,您可以在组件中使用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 - 无法直接访问容器的引用:
这种情况可能发生得更频繁,并且需要更多的代码。 您需要使用React.forwardRef
将父组件的引用传递给子组件。
演示代码可以在下面或下面的Codesandbox中找到
代码中的一些话:
const containerRef = useRef()
创建一个引用,并通过<div ref={containerRef}/>
在主容器中使用它。 在引擎盖下它会做类似ref => containerRef.current=ref
Demo
组件。 为什么不使用React.createRef
?
这也可以,但它会在您的应用程序的每个渲染上重新创建引用。 请查看此处以了解useRef
和createRef
之间的区别。
简而言之,将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>
React-use
中还有一些有用的钩子可以在这里提供帮助。
useWindowSize
和useSize
看起来非常相似,但是在查看源代码之后,第一个依赖于window.onresize
事件并且需要更少的代码来实现。
useSize
将在当前组件( z-index: -1
)下方添加一个 iframe 以使用resize
事件跟踪大小,并且需要更多代码。 它还使用setTimeout
增加了一点去抖动。
因此,如果您只需要宽度/高度来对第一次渲染进行一些计算,请使用useSize
useWindowSize
如果您只需要获取 window 大小,则使用WindowSize 是go的方式。 他们正在使用document.addEventlistener('resize', resizeHandler)
使用onresize 事件并检查innerWidth / innerHeight
Codesandbox Demo
要跟踪元素大小,可以使用useMeasure
。 它在后台使用ResizeObserver
,因此就像上面的代码一样,其中ref
是您要跟踪的引用:
useMeasure
返回的第一个元素是setRef
方法。 因此,您可以在组件中执行以下操作:
const [setRef, { width, height }] = useMeasure();
useEffect(() => {
setRef(ref.current)
}, [])
请看下面的Codesandbox 。
如果您想跟踪组件的大小useSize
可以按照文档中的说明使用。 useSize
Demo 使用大小
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.